{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Title: #Word Transformer LCCI"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Difficulty: #Medium"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Category Title: #LCCI"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tag Slug: #breadth-first-search #hash-table #string #backtracking"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Name Translated: #广度优先搜索 #哈希表 #字符串 #回溯"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Solution Name: findLadders"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Translated Title: #单词转换"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Translated Content:\n",
    "<p>给定字典中的两个词，长度相等。写一个方法，把一个词转换成另一个词， 但是一次只能改变一个字符。每一步得到的新词都必须能在字典中找到。</p>\n",
    "\n",
    "<p>编写一个程序，返回一个可能的转换序列。如有多个可能的转换序列，你可以返回任何一个。</p>\n",
    "\n",
    "<p><strong>示例 1:</strong></p>\n",
    "\n",
    "<pre><strong>输入:</strong>\n",
    "beginWord = &quot;hit&quot;,\n",
    "endWord = &quot;cog&quot;,\n",
    "wordList = [&quot;hot&quot;,&quot;dot&quot;,&quot;dog&quot;,&quot;lot&quot;,&quot;log&quot;,&quot;cog&quot;]\n",
    "\n",
    "<strong>输出:</strong>\n",
    "[&quot;hit&quot;,&quot;hot&quot;,&quot;dot&quot;,&quot;lot&quot;,&quot;log&quot;,&quot;cog&quot;]\n",
    "</pre>\n",
    "\n",
    "<p><strong>示例 2:</strong></p>\n",
    "\n",
    "<pre><strong>输入:</strong>\n",
    "beginWord = &quot;hit&quot;\n",
    "endWord = &quot;cog&quot;\n",
    "wordList = [&quot;hot&quot;,&quot;dot&quot;,&quot;dog&quot;,&quot;lot&quot;,&quot;log&quot;]\n",
    "\n",
    "<strong>输出: </strong>[]\n",
    "\n",
    "<strong>解释:</strong>&nbsp;<em>endWord</em> &quot;cog&quot; 不在字典中，所以不存在符合要求的转换序列。</pre>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Description: [word-transformer-lcci](https://leetcode.cn/problems/word-transformer-lcci/description/)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Solutions: [word-transformer-lcci](https://leetcode.cn/problems/word-transformer-lcci/solutions/)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "test_cases = []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        \n",
    "        def backtrack(res: List[List[str]], node: str, froms, path:List[str]):\n",
    "            if not froms[node]:\n",
    "                res.append(path[::-1])\n",
    "                return\n",
    "            for parent in froms[node]:\n",
    "                path.append(parent)\n",
    "                backtrack(res, parent, froms, path)\n",
    "                path.pop()\n",
    "        \n",
    "        \n",
    "        dic = wordList\n",
    "        res = []\n",
    "        if endWord not in dic:\n",
    "            return res\n",
    "        if beginWord in dic:\n",
    "            dic.remove(beginWord)\n",
    "        steps = {beginWord : 0}\n",
    "        froms = {beginWord : []}\n",
    "        step = 0\n",
    "        found = False\n",
    "        queue = [beginWord]\n",
    "        wordLen = len(beginWord)\n",
    "        while queue:\n",
    "            step += 1\n",
    "            size = len(queue)\n",
    "            for i in range(size):\n",
    "                currWord = queue[0]\n",
    "                queue.pop(0)\n",
    "                nextWord = currWord\n",
    "                for j in range(wordLen):\n",
    "                    origin = nextWord[j]\n",
    "                    for c in range(ord('a'),ord('z') + 1):\n",
    "                        nextWord = nextWord[:j] + chr(c) + nextWord[j + 1:]\n",
    "                        if steps.get(nextWord) == step:\n",
    "                            froms[nextWord].append(currWord)\n",
    "                        if nextWord not in dic:\n",
    "                            continue\n",
    "                        dic.remove(nextWord)\n",
    "                        queue.append(nextWord)\n",
    "                        if nextWord in froms:\n",
    "                            froms[nextWord].append(currWord)\n",
    "                        else:\n",
    "                            froms[nextWord] = [currWord]\n",
    "                        steps[nextWord] = step\n",
    "                        if nextWord == endWord:\n",
    "                            found = True\n",
    "                    nextWord = nextWord[:j] + origin + nextWord[j + 1:]\n",
    "            if found:\n",
    "                break\n",
    "        \n",
    "        if found:\n",
    "            path = [endWord]\n",
    "            backtrack(res,endWord,froms,path)\n",
    "        \n",
    "        return res\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        if endWord not in wordList: return []\n",
    "        idx_start, idx_end = 0, 0\n",
    "        if beginWord not in wordList: \n",
    "            wordList.append(beginWord)\n",
    "            idx_start = len(wordList)-1\n",
    "            idx_end = wordList.index(endWord)\n",
    "        else: \n",
    "            idx_start = wordList.index(beginWord)\n",
    "            idx_end = wordList.index(endWord)\n",
    "        N, n, m = 505, len(wordList), len(wordList[0])\n",
    "        dis = [0x3f3f3f3f for i in range(N)]\n",
    "        edges = [[] for i in range(N)]\n",
    "        pre = [[] for i in range(N)]\n",
    "        st, temp, ans = [False] * N, [endWord], []\n",
    "\n",
    "        def check(a: int, b: int) -> bool:\n",
    "            cnt = 0\n",
    "            for i in range(m):\n",
    "                if a[i] != b[i]:\n",
    "                    cnt += 1\n",
    "                    if cnt > 1:\n",
    "                        return False\n",
    "            return True\n",
    "\n",
    "        def djs() -> None:\n",
    "            dis[idx_start] = 0\n",
    "            for i in range(n):\n",
    "                t = -1\n",
    "                for j in range(n):\n",
    "                    if not st[j] and (t == -1 or dis[j] < dis[t]):\n",
    "                        t = j\n",
    "                st[t] = True\n",
    "                for j in edges[t]:\n",
    "                    if dis[j] > dis[t] + 1:\n",
    "                        dis[j] = dis[t] + 1\n",
    "                        pre[j] = [t]\n",
    "                    elif dis[j] == dis[t] + 1:\n",
    "                        pre[j].append(t)\n",
    "        \n",
    "        def dfs(u: int) -> None:\n",
    "            nonlocal ans\n",
    "            if pre[u] == [] and wordList[u] != endWord:\n",
    "                ans.append(list(reversed(temp)))\n",
    "                return\n",
    "            for i in pre[u]:\n",
    "                temp.append(wordList[i])\n",
    "                dfs(i)\n",
    "                temp.pop()\n",
    "\n",
    "        for i in range(n):\n",
    "            for j in range(i+1, n):\n",
    "                if check(wordList[i], wordList[j]):\n",
    "                    edges[i].append(j)\n",
    "                    edges[j].append(i)\n",
    "        djs()\n",
    "        dfs(idx_end)\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        self.result = []\n",
    "        wordList = set(wordList)\n",
    "        if not endWord in wordList:\n",
    "            return self.result\n",
    "        self.dist = {}\n",
    "        self.bfs(beginWord, endWord, wordList)\n",
    "        path = [endWord]\n",
    "        self.dfs(endWord, path, beginWord)\n",
    "        return self.result\n",
    "\n",
    "    def dfs(self, root, path, beginWord):\n",
    "        if root == beginWord:\n",
    "            self.result.append(path[::-1])\n",
    "            return\n",
    "        for i in range(len(root)):\n",
    "            for index in range(97, 123):\n",
    "                temproot = root[:i] + chr(index) + root[i+1:]\n",
    "                if temproot in self.dist.keys() and self.dist[temproot] == self.dist[root] - 1:\n",
    "                    path.append(temproot)\n",
    "                    self.dfs(temproot, path, beginWord)\n",
    "                    path.pop()\n",
    "                \n",
    "    def bfs(self, beginWord, endWord, wordList):  \n",
    "        queue = []\n",
    "        self.dist[beginWord] = 0\n",
    "        queue.append(beginWord)\n",
    "\n",
    "        while len(queue) != 0:\n",
    "            for q in range(len(queue)):\n",
    "                word = queue.pop(0)\n",
    "                for i in range(len(word)):\n",
    "                    for index in range(97,123):\n",
    "                        tempword = word[:i] + chr(index) + word[i+1:]\n",
    "                        if tempword in wordList and tempword not in self.dist:\n",
    "                            self.dist[tempword] = self.dist[word] + 1\n",
    "                            if tempword == endWord:\n",
    "                                return\n",
    "                            queue.append(tempword)\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "       \n",
    "        \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import copy\n",
    "class Solution:\n",
    "   \n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        # 建立转换图\n",
    "        # 用dijkstra方法算出从endword到各个点的距离\n",
    "        # 发布 恶搞之家 饺子和狗 那集的朋友圈\n",
    "        # 从beginword用dfs回溯距离\n",
    "        # checkdiff 1表示可转化\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "        if beginWord not in wordList:\n",
    "            wordList.append(beginWord)\n",
    "        graph = collections.defaultdict(list)\n",
    "        \n",
    "        beginidx = wordList.index(beginWord)\n",
    "        endidx = wordList.index(endWord)\n",
    "        # 连通图\n",
    "        for idx1 in range(len(wordList)):\n",
    "            for idx2 in range(len(wordList)):\n",
    "                if idx1 == idx2:\n",
    "                    continue\n",
    "                if self.checkdiff(wordList[idx1], wordList[idx2]):\n",
    "                    graph[idx1].append(idx2)\n",
    "\n",
    "        # dijkstra\n",
    "        q = [[0, endidx]]\n",
    "        visited = [False]*len(wordList)\n",
    "        dist = [float('inf')] * len(wordList)\n",
    "        while q:\n",
    "            mindist, curidx = heapq.heappop(q)\n",
    "            if visited[curidx] == True:\n",
    "                continue\n",
    "            visited[curidx] = True\n",
    "            dist[curidx] = mindist\n",
    "            for i in graph[curidx]:\n",
    "                if visited[i] == False and dist[i]> 1+mindist:\n",
    "                    heapq.heappush(q,[1+mindist, i])\n",
    "        print(wordList)\n",
    "        mindist = dist[beginidx]\n",
    "        print(dist)\n",
    "        res = []\n",
    "        # 用dfs回溯,从begin开始依次寻找dist-1的点直到end\n",
    "        def dfs(curidx_, temp):\n",
    "           \n",
    "            if dist[curidx_]==0:\n",
    "                \n",
    "                res.append(copy.deepcopy(temp))\n",
    "                return\n",
    "            curdist = dist[curidx_]\n",
    "            for node in graph[curidx_]:\n",
    "                if dist[node] == curdist-1: # inf和inf-1大小相等\n",
    "                    temp.append(wordList[node])\n",
    "                    dfs(node, temp)\n",
    "                    temp.pop()\n",
    "            return\n",
    "        temp_ = [beginWord]\n",
    "        if dist[beginidx] == float('inf'):\n",
    "            return []\n",
    "        dfs(beginidx, temp_)\n",
    "        return res    \n",
    "\n",
    "\n",
    "\n",
    "\n",
    "    \n",
    "\n",
    "        \n",
    "    def checkdiff(self, str1, str2):\n",
    "        diff = 0\n",
    "        for q, r in zip(str1, str2):\n",
    "            if q != r:\n",
    "                diff += 1\n",
    "        if diff != 1:\n",
    "            return False\n",
    "        return True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "  \n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "        edgeToNodes = defaultdict(list)\n",
    "        n = len(beginWord)\n",
    "        wordList.append(beginWord)\n",
    "        for word in wordList:\n",
    "            for j in range(n):\n",
    "                pattern = word[:j] + '*' + word[j+1:]\n",
    "                edgeToNodes[pattern].append(word)\n",
    "\n",
    "        def BFS() -> int:\n",
    "            \n",
    "            Q = deque([beginWord])\n",
    "            visited = set([beginWord])   \n",
    "            res = 1                 \n",
    "            while Q:\n",
    "                for _ in range(len(Q)):\n",
    "                    word = Q.popleft()\n",
    "                    Layers[res].append(word)\n",
    "                    if word == endWord:\n",
    "                        return res\n",
    "                    for j in range(n):\n",
    "                        pattern = word[:j] + '*' + word[j+1:]\n",
    "                        for node in edgeToNodes[pattern]:\n",
    "                            if node not in visited:\n",
    "                                Q.append(node)\n",
    "                                visited.add(node)\n",
    "                res += 1 \n",
    "            return 0 \n",
    "        Layers = defaultdict(list)\n",
    "        depth  = BFS()\n",
    "        ans = []\n",
    "\n",
    "        def DFS(word, lay):\n",
    "            if lay == 1:\n",
    "                ans.append(path[::-1])\n",
    "                return\n",
    "            for j in range(n):\n",
    "                pattern = word[:j] + '*' + word[j+1:]\n",
    "                for node in Layers[lay-1]:\n",
    "                    if node in edgeToNodes[pattern]:\n",
    "                        path.append(node)\n",
    "                        DFS(node, lay-1)\n",
    "                        path.pop()\n",
    "        path = [endWord]\n",
    "        DFS(endWord,depth)\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import deque\n",
    "class Node:\n",
    "    def __init__(self, key, pre=None):\n",
    "        self.key = key\n",
    "        self.pre = pre\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord, endWord, wordList):\n",
    "        word_dict = set(wordList)\n",
    "        visited = {beginWord: [1, []]}\n",
    "        queue = deque([(beginWord, 1)])\n",
    "        result = []\n",
    "        while queue:\n",
    "            pop, depth = queue.popleft()\n",
    "            if pop == endWord:\n",
    "                def travers(node):\n",
    "                    r = [node.key]\n",
    "                    while node.pre:\n",
    "                        r.insert(0, node.pre.key)\n",
    "                        node = node.pre\n",
    "                    return r[len(r)-1:: -1]\n",
    "                result = []\n",
    "                q = deque([Node(pop)])\n",
    "                while len(q):\n",
    "                    node = q.pop()\n",
    "                    if len(visited[node.key][1]) > 0:\n",
    "                        for new in visited[node.key][1]:\n",
    "                            q.append(Node(new, node))\n",
    "                    else:\n",
    "                        result.append(travers(node))\n",
    "                return result\n",
    "                \n",
    "\n",
    "            for i in range(len(pop)):\n",
    "                for j in range(97, 123):\n",
    "                    new_word = pop[:i] + chr(j) + pop[i+1:]\n",
    "                    if new_word in word_dict:\n",
    "                        if new_word not in visited:\n",
    "                            queue.append((new_word, depth + 1))\n",
    "                            visited[new_word] = (depth + 1, [pop]) \n",
    "                        elif visited[new_word][0] == depth + 1:\n",
    "                            visited[new_word][1].append(pop)\n",
    "        return []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        # 定义答案\n",
    "        ans = []\n",
    "        # 转为set，判断是否存在快很多， 不然127题就会超时\n",
    "        wordList = set(wordList)\n",
    "\n",
    "        # 终点如果不存在于单词中，直接返回\n",
    "        if endWord not in wordList:\n",
    "            return ans\n",
    "\n",
    "        # 我们下面题解中会多次用到一个单词对应的路径的最短距离：\n",
    "        # 这个是指这个单词在最短路径中离beginWord或者离endWord的距离（根据方向不同，降序升序也有不同）\n",
    "\n",
    "        # 首先先用一遍bfs去找到终点对应的路径的最短距离\n",
    "        # 这里用dist记录从beginWord到某个单词的最短距离，遇到endWord就跳出\n",
    "        # 这样子最后符合条件的最短路径中终点之前的单词的最短路径的距离也会被保存下来\n",
    "        dist = {}\n",
    "        dist[beginWord] = 0\n",
    "\n",
    "        # BFS\n",
    "        st = collections.deque()\n",
    "        st.append(beginWord)\n",
    "\n",
    "        def f():\n",
    "            while st:\n",
    "                q = st.popleft()\n",
    "                for xx in range(len(q)):\n",
    "                    for index in range(97, 123):\n",
    "                        tempq = q[:xx] + chr(index) + q[xx + 1:]\n",
    "                        if tempq in wordList and tempq not in dist:\n",
    "                            dist[tempq] = dist[q] + 1\n",
    "                            if tempq == endWord:\n",
    "                                return\n",
    "                            st.append(tempq)\n",
    "\n",
    "        f()\n",
    "        # BFS end\n",
    "\n",
    "        # 重点来了，敲黑板\n",
    "        # 因为我们前面找最短长度时候，是顺着找，其实是有很多路径试错的\n",
    "        # 特别是加的那个第32个测试用例，\"aaaaa\"，\"ggggg\"那个\n",
    "        # 如果我们再找路径的时候还是和上面的一样顺着遍历， 我pycharm跑了好久都没跑出来， 试错路径太多了\n",
    "\n",
    "        # 这里我们反着来， 正着找和反着找，试错的路径会有很多不一样，但是能到终点的正确的路径是会包含的\n",
    "        # 为何？ 这里要体会一下，因为我们在第一步中仅仅是找到路径的长度\n",
    "        # 并且！ 所有比目标矮一级的单词我们都找到了(bfs性质)\n",
    "\n",
    "        # 第一步中找到的节点对应的长度只是所有节点的子集， 下面这里也只用到了路径的长度这一个信息\n",
    "\n",
    "        # 从终点开始遍历， 那么越离起点进，dist里面值是越小的\n",
    "        # 所以判断是dist[root] == dist[temproot] + 1:\n",
    "        # 当前单词的距离 = 改一个字母的单词的距离 + 1\n",
    "        path = [endWord]\n",
    "\n",
    "        def bfs(root):\n",
    "            # 遇到起点，反向，加入答案\n",
    "            if root == beginWord:\n",
    "                ans.append(path[::-1])\n",
    "            else:\n",
    "                for xx in range(len(root)):\n",
    "                    for index in range(97, 123):\n",
    "                        # temproot是改变了一个单词的root\n",
    "                        temproot = root[:xx] + chr(index) + root[xx + 1:]\n",
    "                        # 重点来了，如果temproot的高度我们获取到了\n",
    "                        # 那么最短路径是可能包含这个单词的（也可能不包含，得试）\n",
    "                        # 然后如果我们下一个遍历的单词的长度是\n",
    "                        if temproot in dist and dist[root] == dist[temproot] + 1:\n",
    "                            path.append(temproot)\n",
    "                            bfs(temproot)\n",
    "                            path.pop()\n",
    "\n",
    "        bfs(endWord)\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        class Node:\n",
    "            def __init__(self,val=0):\n",
    "                self.val=val\n",
    "                self.pre=[]\n",
    "\n",
    "        def isNeighbor(w1,w2):\n",
    "            diff_count=0\n",
    "            for i in range(len(w1)):\n",
    "                if w1[i]!=w2[i]:\n",
    "                    diff_count+=1\n",
    "                    if diff_count>1:\n",
    "                        return False\n",
    "            return True\n",
    "\n",
    "        def outputAnswer(node):\n",
    "            if len(node.pre)==0:\n",
    "                return [[node.val]]\n",
    "            result=[]\n",
    "            for n in node.pre:\n",
    "                _r=outputAnswer(n)\n",
    "                for item in _r:\n",
    "                    result.append(item+[node.val])\n",
    "            return result\n",
    "\n",
    "\n",
    "        if isNeighbor(beginWord,endWord):\n",
    "            return [[beginWord,endWord]]\n",
    "        head=Node(beginWord)\n",
    "        tail=None\n",
    "        curLayer=[head]\n",
    "        wordNodes=list()\n",
    "        for word in wordList:\n",
    "            if word==beginWord: \n",
    "                continue\n",
    "            if word==endWord:\n",
    "                tail=Node(endWord)\n",
    "                continue\n",
    "            wordNodes.append(Node(word))\n",
    "        if not tail:\n",
    "            return []\n",
    "        while len(curLayer)>0:\n",
    "            is_solved=False\n",
    "            neighborList=[]\n",
    "            for i in range(len(wordNodes)-1,-1,-1):\n",
    "                node=wordNodes[i]\n",
    "                is_selected=False\n",
    "                for layer_node in curLayer:\n",
    "                    if not isNeighbor(layer_node.val,node.val):\n",
    "                        continue\n",
    "                    if not is_selected:\n",
    "                        neighborList.append(node)\n",
    "                        is_selected=True\n",
    "                        if isNeighbor(node.val,endWord):\n",
    "                            is_solved=True\n",
    "                            tail.pre.append(node)\n",
    "                    node.pre.append(layer_node)\n",
    "                if is_selected:\n",
    "                    wordNodes.pop(i)        \n",
    "            if is_solved:\n",
    "                return outputAnswer(tail)\n",
    "            else:\n",
    "                curLayer=neighborList\n",
    "        return []\n",
    "            \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        if endWord not in wordList or len(beginWord)!=len(endWord):\n",
    "            return []\n",
    "        forward={beginWord}\n",
    "        backward={endWord}\n",
    "        dic=defaultdict(list)\n",
    "        reverse=True\n",
    "        wordSet=set(wordList)\n",
    "        wordLength=len(beginWord)\n",
    "        letters=\"abcdefghijklmnopqrstuvwxyz\"\n",
    "        results=[]\n",
    "        while forward:\n",
    "            if len(forward)<len(backward):\n",
    "                forward,backward,reverse=backward,forward,not reverse\n",
    "            wordSet-=forward\n",
    "            cur=set()\n",
    "            for word in forward:\n",
    "                for i in range(wordLength):\n",
    "                    left,right=word[:i],word[i+1:]\n",
    "                    for c in letters:\n",
    "                        w=left+c+right\n",
    "                        if w in wordSet:\n",
    "                            cur.add(w)\n",
    "                            if reverse:\n",
    "                                dic[w].append(word)\n",
    "                            else:\n",
    "                                dic[word].append(w)\n",
    "            forward=cur\n",
    "            if cur&backward:\n",
    "                results=[[endWord]]\n",
    "                while results[0][0]!=beginWord:\n",
    "                    results=[[x]+i for i in results for x in dic[i[0]]]\n",
    "                return results\n",
    "        return []\n",
    "\n",
    "\n",
    "\n",
    "        \n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import copy\n",
    "class Solution:\n",
    "    def __init__(self):\n",
    "        self.word2level = dict()\n",
    "        self.come_from = collections.defaultdict(list)\n",
    "        self.res = []\n",
    "\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        # step 1: 用广度优先搜索，为每一个队列分配一个level，并记录每个word可以由哪些word组成\n",
    "        found = self.bfs(beginWord, endWord, wordList)\n",
    "        if not found:\n",
    "            return []\n",
    "        # step 2: 用深度优先搜索，从endword出发，找寻到beginword的路径\n",
    "        self.back_track(endWord, beginWord, [endWord])\n",
    "        return self.res\n",
    "\n",
    "    def back_track(self, endWord, beginWord, path):\n",
    "        if endWord == beginWord:\n",
    "            self.res.append(path[::-1])\n",
    "            return\n",
    "        q = self.come_from[endWord]\n",
    "        for w in q:\n",
    "            path.append(w)\n",
    "            self.back_track(w, beginWord, path)\n",
    "            path.pop(-1)\n",
    "        return\n",
    "    \n",
    "    def bfs(self, beginWord, endWord, wordList) -> bool:\n",
    "        q = []\n",
    "        q.append(beginWord)\n",
    "        level = 0\n",
    "        found = False\n",
    "        while q:\n",
    "            next_q = set()\n",
    "            for w in q:\n",
    "                # 记录w所在的层数\n",
    "                self.word2level[w] = level\n",
    "                if w == endWord:\n",
    "                    found = True\n",
    "            for w in q:\n",
    "                # 找寻w的下一个单词\n",
    "                next_words = self.find_next(w, wordList)\n",
    "                for nw in next_words:\n",
    "                    next_q.add(nw)\n",
    "                    self.come_from[nw].append(w)\n",
    "                # 记录单词的前驱\n",
    "            q = list(next_q)\n",
    "            level += 1\n",
    "        return found\n",
    "\n",
    "    def find_next(self, word, wordList):\n",
    "        next_words = []\n",
    "        length = len(word)\n",
    "        for i in range(length):\n",
    "            for j in range(26):\n",
    "                ch = chr(ord('a') + j)\n",
    "                if ch == word[i]:\n",
    "                    continue\n",
    "                try_word = word[:i] + ch + word[i + 1:]\n",
    "                if try_word in self.word2level:\n",
    "                    continue\n",
    "                if try_word in wordList:\n",
    "                    next_words.append(try_word)\n",
    "        return next_words\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "        \n",
    "        if beginWord not in wordList:\n",
    "            wordList.append(beginWord)\n",
    "\n",
    "        begin = wordList.index(beginWord)\n",
    "        end = wordList.index(endWord)\n",
    "        n = len(wordList)\n",
    "        edges = [[] for _ in range(n)]\n",
    "\n",
    "        for i in range(n):\n",
    "            for j in range(i + 1, n):\n",
    "                diff = sum(1 for k in range(len(wordList[i])) if wordList[i][k] != wordList[j][k])\n",
    "                if diff == 1:\n",
    "                    edges[i].append(j)\n",
    "                    edges[j].append(i)\n",
    "        \n",
    "        found = False\n",
    "        q = deque([begin])\n",
    "        levelCur = 0\n",
    "        levels = [-1] * n\n",
    "        levels[begin] = 0\n",
    "\n",
    "        while len(q):\n",
    "            length = len(q)\n",
    "            levelCur += 1\n",
    "            for _ in range(length):\n",
    "                u = q.popleft()\n",
    "                \n",
    "                if u == end:\n",
    "                    found = True\n",
    "                \n",
    "                for to in edges[u]:\n",
    "                    if levels[to] == -1:      \n",
    "                        q.append(to)\n",
    "                        levels[to] = levelCur\n",
    "\n",
    "        res = []\n",
    "\n",
    "        def dfs(u, path, levelCur):\n",
    "            \n",
    "            if u == begin:\n",
    "                res.append([wordList[i] for i in path[::-1]])\n",
    "                return \n",
    "\n",
    "            for to in edges[u]:\n",
    "                if levels[to] == levelCur:\n",
    "                    dfs(to, path + [to], levelCur - 1)\n",
    "\n",
    "        if found:\n",
    "            dfs(end, [end], levels[end] - 1)\n",
    "\n",
    "        return res\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        s = 'abcdefghijklmnopqrstuvwxyz'\n",
    "        l = len(beginWord)\n",
    "        wordSet = set([word for word in wordList if len(word)==l])\n",
    "        wordSet.discard(beginWord)\n",
    "        if endWord not in wordSet:\n",
    "            return []\n",
    "        \n",
    "        Q = deque([(beginWord,1)])\n",
    "        word_links = dict()\n",
    "        minEndDeep = 1e3\n",
    "        curDeep = 1\n",
    "        nextDeepWords = set()\n",
    "        while Q:\n",
    "            word, deep = Q.pop()\n",
    "            if curDeep == minEndDeep:\n",
    "                break\n",
    "            if curDeep < deep:\n",
    "                curDeep = deep\n",
    "                nextDeepWords = set()\n",
    "            for i in range(l):\n",
    "                for c in s:\n",
    "                    nextWord = word[:i] + c + word[i+1:]\n",
    "                    if nextWord == endWord:\n",
    "                        minEndDeep = min(minEndDeep, deep+1)\n",
    "                    if nextWord in nextDeepWords:\n",
    "                        word_links[nextWord].append(word)\n",
    "                    elif nextWord in wordSet:\n",
    "                        word_links[nextWord] = [word]\n",
    "                        nextDeepWords.add(nextWord)\n",
    "                        wordSet.remove(nextWord)\n",
    "                        Q.appendleft((nextWord, deep+1))\n",
    "        if endWord not in word_links:\n",
    "            return []\n",
    "        ress = []\n",
    "        def dfs(word, res):\n",
    "            res.append(word)\n",
    "            if word == beginWord:\n",
    "                ress.append(res[::-1])\n",
    "            else:\n",
    "                for preWord in word_links[word]:\n",
    "                    dfs(preWord, res[:])\n",
    "        dfs(endWord, [])\n",
    "        return ress\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        ans = []\n",
    "        if endWord not in wordList:\n",
    "            return ans\n",
    "        size = len(beginWord)\n",
    "        cur_word_set = {beginWord}\n",
    "        ws = set(wordList)\n",
    "        # 用于控制bfs结束\n",
    "        flag = False\n",
    "        if beginWord in ws:\n",
    "             ws.remove(beginWord)\n",
    "        tmp = list('abcdefghijklmnopqrstuvwxyz')\n",
    "        # key为当前单词，value为能到达该单词（bfs搜索）的单词列表，即该单词的parent\n",
    "        word_dict = {}\n",
    "        # bfs\n",
    "        while cur_word_set:\n",
    "            # 该次bfs匹配到的单词\n",
    "            match_set = set()\n",
    "            for cur in cur_word_set:\n",
    "                for i in range(size):\n",
    "                    for j in tmp:\n",
    "                        if cur[i] == j:\n",
    "                            continue\n",
    "                        word = cur[:i] + j + cur[i + 1:]\n",
    "                        # word在单词列表中\n",
    "                        if word in ws:\n",
    "                            # 匹配加入该单词\n",
    "                            match_set.add(word)\n",
    "                            # 为该单词维护parent\n",
    "                            if word not in word_dict:\n",
    "                                word_dict[word] = []\n",
    "                            word_dict[word].append(cur)\n",
    "                            # 到达终点 bfs结束\n",
    "                            if word == endWord:\n",
    "                                flag = True\n",
    "            # 该次bfs结束，剔除掉匹配到的单词\n",
    "            for el in match_set:\n",
    "                ws.remove(el)\n",
    "            # 下次bfs的parent\n",
    "            cur_word_set = match_set\n",
    "            if flag: break\n",
    "        # 完成bfs开始dfs,通过endword反向找parent,直到找到beginword\n",
    "\n",
    "        # 没有匹到endword,直接结束\n",
    "        if not flag: return ans\n",
    "        result = [endWord]\n",
    "        def dfs(cur_word):\n",
    "            if cur_word == beginWord:\n",
    "                ans.append(result[::-1])\n",
    "                return\n",
    "            for el in word_dict[cur_word]:\n",
    "                result.append(el)\n",
    "                dfs(el)\n",
    "                result.pop()\n",
    "\n",
    "        dfs(endWord)\n",
    "        return ans\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        ans = []\n",
    "        if endWord not in wordList:\n",
    "            return ans\n",
    "        size = len(beginWord)\n",
    "        cur_word_set = {beginWord}\n",
    "        ws = set(wordList)\n",
    "        # 用于控制bfs结束\n",
    "        flag = False\n",
    "        if beginWord in ws:\n",
    "             ws.remove(beginWord)\n",
    "        tmp = list('abcdefghijklmnopqrstuvwxyz')\n",
    "        # key为当前单词，value为能到达该单词（bfs搜索）的单词列表，即该单词的parent\n",
    "        word_dict = {}\n",
    "        # bfs\n",
    "        while cur_word_set:\n",
    "            # 该次bfs匹配到的单词\n",
    "            match_set = set()\n",
    "            for cur in cur_word_set:\n",
    "                for i in range(size):\n",
    "                    for j in tmp:\n",
    "                        if cur[i] == j:\n",
    "                            continue\n",
    "                        word = cur[:i] + j + cur[i + 1:]\n",
    "                        # word在单词列表中\n",
    "                        if word in ws:\n",
    "                            # 匹配加入该单词\n",
    "                            match_set.add(word)\n",
    "                            # 为该单词维护parent\n",
    "                            if word not in word_dict:\n",
    "                                word_dict[word] = []\n",
    "                            word_dict[word].append(cur)\n",
    "                            # 到达终点 bfs结束\n",
    "                            if word == endWord:\n",
    "                                flag = True\n",
    "            # 该次bfs结束，剔除掉匹配到的单词\n",
    "            for el in match_set:\n",
    "                ws.remove(el)\n",
    "            # 下次bfs的parent\n",
    "            cur_word_set = match_set\n",
    "            if flag: break\n",
    "        # 完成bfs开始dfs,通过endword反向找parent,直到找到beginword\n",
    "\n",
    "        # 没有匹到endword,直接结束\n",
    "        if not flag: return ans\n",
    "        result = [endWord]\n",
    "        def dfs(cur_word):\n",
    "            if cur_word == beginWord:\n",
    "                ans.append(result[::-1])\n",
    "                return\n",
    "            for el in word_dict[cur_word]:\n",
    "                result.append(el)\n",
    "                dfs(el)\n",
    "                result.pop()\n",
    "\n",
    "        dfs(endWord)\n",
    "        return ans\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import defaultdict, deque\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord, endWord, wordList):\n",
    "        res = []\n",
    "        word_set = set(wordList)\n",
    "        wlen=len(beginWord)\n",
    "        if endWord not in word_set: return res\n",
    "        word_set.discard(beginWord)\n",
    "        q=deque([beginWord])\n",
    "        from_dict=defaultdict(set)\n",
    "        steps={beginWord:0}\n",
    "        step=0\n",
    "        flag=False\n",
    "        #step1\n",
    "        while q:\n",
    "            size=len(q)\n",
    "            step+=1\n",
    "            for _ in range(size):\n",
    "                curr=q.popleft()\n",
    "                nex_lst=list(curr)\n",
    "                for j in range(wlen):\n",
    "                    origin=nex_lst[j]\n",
    "                    for c in range(ord('a'),ord('z')+1):\n",
    "                        nex_lst[j]=chr(c)\n",
    "                        next_word=\"\".join(nex_lst)\n",
    "                        if steps.get(next_word,-1)==step:\n",
    "                            from_dict[next_word].add(curr)\n",
    "                        if next_word not in word_set:\n",
    "                            continue\n",
    "                        word_set.discard(next_word)\n",
    "                        q.append(next_word)\n",
    "                        from_dict[next_word].add(curr)\n",
    "                        steps[next_word]=step\n",
    "                        if next_word==endWord:\n",
    "                            flag=True\n",
    "                    nex_lst[j]=origin\n",
    "            if flag: break\n",
    "        if flag:\n",
    "            path = [endWord]\n",
    "            self.backtrack(res, endWord, from_dict, path)\n",
    "        return res\n",
    "\n",
    "    def backtrack(self, res, node, from_dict, path):\n",
    "        if not from_dict[node]:\n",
    "            res.append(path[::-1])\n",
    "            return\n",
    "        for parent in from_dict[node]:\n",
    "            path.append(parent)\n",
    "            self.backtrack(res, parent, from_dict, path)\n",
    "            path.pop()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        ans = []\n",
    "        if endWord not in wordList:\n",
    "            return ans\n",
    "        size = len(beginWord)\n",
    "        cur_word_set = {beginWord}\n",
    "        ws = set(wordList)\n",
    "        # 用于控制bfs结束\n",
    "        flag = False\n",
    "        if beginWord in ws:\n",
    "             ws.remove(beginWord)\n",
    "        tmp = list('abcdefghijklmnopqrstuvwxyz')\n",
    "        # key为当前单词，value为能到达该单词（bfs搜索）的单词列表，即该单词的parent\n",
    "        word_dict = {}\n",
    "        # bfs\n",
    "        while cur_word_set:\n",
    "            # 该次bfs匹配到的单词\n",
    "            match_set = set()\n",
    "            for cur in cur_word_set:\n",
    "                for i in range(size):\n",
    "                    for j in tmp:\n",
    "                        if cur[i] == j:\n",
    "                            continue\n",
    "                        word = cur[:i] + j + cur[i + 1:]\n",
    "                        # word在单词列表中\n",
    "                        if word in ws:\n",
    "                            # 匹配加入该单词\n",
    "                            match_set.add(word)\n",
    "                            # 为该单词维护parent\n",
    "                            if word not in word_dict:\n",
    "                                word_dict[word] = []\n",
    "                            word_dict[word].append(cur)\n",
    "                            # 到达终点 bfs结束\n",
    "                            if word == endWord:\n",
    "                                flag = True\n",
    "            # 该次bfs结束，剔除掉匹配到的单词\n",
    "            for el in match_set:\n",
    "                ws.remove(el)\n",
    "            # 下次bfs的parent\n",
    "            cur_word_set = match_set\n",
    "            if flag: break\n",
    "        # 完成bfs开始dfs,通过endword反向找parent,直到找到beginword\n",
    "\n",
    "        # 没有匹到endword,直接结束\n",
    "        if not flag: return ans\n",
    "        result = [endWord]\n",
    "        def dfs(cur_word):\n",
    "            if cur_word == beginWord:\n",
    "                ans.append(result[::-1])\n",
    "                return\n",
    "            for el in word_dict[cur_word]:\n",
    "                result.append(el)\n",
    "                dfs(el)\n",
    "                result.pop()\n",
    "\n",
    "        dfs(endWord)\n",
    "        return ans\n",
    "                                    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        dist = collections.defaultdict(int)\n",
    "        word_set = set(wordList)\n",
    "        dist[beginWord] = 1\n",
    "        deque = collections.deque([beginWord])\n",
    "        while(deque):\n",
    "            word = deque.popleft()\n",
    "            for index in range(len(word)):\n",
    "                for char_num in range(97,123):\n",
    "                    new_word = word[:index] + chr(char_num) + word[index+1:]\n",
    "                    if new_word not in dist and new_word in word_set:\n",
    "                        dist[new_word] = dist[word]+1\n",
    "                        deque.append(new_word)\n",
    "                        if new_word == endWord:\n",
    "                            break\n",
    "        path = [endWord]\n",
    "        ans = []\n",
    "        def bfs(temp_word):\n",
    "            if temp_word == beginWord:\n",
    "                ans.append(path[::-1])\n",
    "                return\n",
    "            for pos in range(len(temp_word)):\n",
    "                for char in range(97,123):\n",
    "                    next_word = temp_word[:pos] + chr(char) + temp_word[pos+1:]\n",
    "                    if next_word in dist and dist[next_word] == dist[temp_word]-1:\n",
    "                    # if next_word in dist and dist[next_word] == dist[temp_word]-1:\n",
    "                        path.append(next_word)\n",
    "                        bfs(next_word)\n",
    "                        path.pop()\n",
    "        bfs(endWord)\n",
    "        return ans \n",
    "        # path = [endWord]\n",
    "        # ans = []\n",
    "        # def bfs(temp_word):\n",
    "        #     if temp_word == beginWord:\n",
    "        #         ans.append(path[::-1])\n",
    "        #         return\n",
    "        #     for pos in range(len(temp_word)):\n",
    "        #         for char in range(97,123):\n",
    "        #             next_word = temp_word[:pos] + chr(char) + temp_word[pos+1:]\n",
    "        #             if next_word in dist and dist[next_word] == dist[temp_word]-1:\n",
    "        #                 # 找到一条路径\n",
    "        #                 path.append(next_word)\n",
    "        #                 bfs(next_word)\n",
    "        #                 path.pop()\n",
    "        # bfs(endWord)\n",
    "        # return ans "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        # 定义答案\n",
    "        ans = []\n",
    "        # 转为set，判断是否存在快很多， 不然127题就会超时\n",
    "        wordList = set(wordList)\n",
    "\n",
    "        # 终点如果不存在于单词中，直接返回\n",
    "        if endWord not in wordList:\n",
    "            return ans\n",
    "\n",
    "        # 我们下面题解中会多次用到一个单词对应的路径的最短距离： \n",
    "        # 这个是指这个单词在最短路径中离beginWord或者离endWord的距离（根据方向不同，降序升序也有不同）\n",
    "\n",
    "\n",
    "        # 首先先用一遍bfs去找到终点对应的路径的最短距离\n",
    "        # 这里用dist记录从beginWord到某个单词的最短距离，遇到endWord就跳出\n",
    "        # 这样子最后符合条件的最短路径中终点之前的单词的最短路径的距离也会被保存下来\n",
    "        dist = {}\n",
    "        dist[beginWord] = 0\n",
    "\n",
    "        # BFS\n",
    "        st = collections.deque()\n",
    "        st.append(beginWord)\n",
    "        def f():\n",
    "            while st:\n",
    "                q = st.popleft()\n",
    "                for xx in range(len(q)):\n",
    "                    for index in range(97, 123):\n",
    "                        tempq = q[:xx] + chr(index) +q[xx+1:]\n",
    "                        if tempq in wordList and tempq not in dist:\n",
    "                            dist[tempq] = dist[q] + 1\n",
    "                            if tempq == endWord:\n",
    "                                return\n",
    "                            st.append(tempq)\n",
    "        f()\n",
    "        # BFS end\n",
    "\n",
    "\n",
    "        # 重点来了，敲黑板\n",
    "        # 因为我们前面找最短长度时候，是顺着找，其实是有很多路径试错的\n",
    "        # 特别是加的那个第32个测试用例，\"aaaaa\"，\"ggggg\"那个\n",
    "        # 如果我们再找路径的时候还是和上面的一样顺着遍历， 我pycharm跑了好久都没跑出来， 试错路径太多了\n",
    "\n",
    "        # 这里我们反着来， 正着找和反着找，试错的路径会有很多不一样，但是能到终点的正确的路径是会包含的\n",
    "        # 为何？ 这里要体会一下，因为我们在第一步中仅仅是找到路径的长度\n",
    "        # 并且！ 所有比目标矮一级的单词我们都找到了(bfs性质)\n",
    "        \n",
    "        # 第一步中找到的节点对应的长度只是所有节点的子集， 下面这里也只用到了路径的长度这一个信息\n",
    "\n",
    "        # 从终点开始遍历， 那么越离起点进，dist里面值是越小的\n",
    "        # 所以判断是dist[root] == dist[temproot] + 1:\n",
    "        # 当前单词的距离 = 改一个字母的单词的距离 + 1\n",
    "        path = [endWord]\n",
    "        def bfs(root):\n",
    "            # 遇到起点，反向，加入答案\n",
    "            if root == beginWord:\n",
    "                ans.append(path[::-1])\n",
    "            else:\n",
    "                for xx in range(len(root)):\n",
    "                    for index in range(97, 123):\n",
    "                        # temproot是改变了一个单词的root\n",
    "                        temproot = root[:xx] + chr(index) + root[xx + 1:]\n",
    "                        # 重点来了，如果temproot的高度我们获取到了\n",
    "                        # 那么最短路径是可能包含这个单词的（也可能不包含，得试）\n",
    "                        # 然后如果我们下一个遍历的单词的长度是\n",
    "                        if temproot in dist and dist[root] == dist[temproot] + 1:\n",
    "                            path.append(temproot)\n",
    "                            bfs(temproot)\n",
    "                            path.pop()\n",
    "\n",
    "        bfs(endWord)\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        wordSet=set(wordList)\n",
    "        if endWord not in wordSet:\n",
    "            return []\n",
    "        if beginWord in wordSet:\n",
    "           wordSet.remove(beginWord)\n",
    "        size=len(beginWord)\n",
    "        letters=list('abcdefghijklmnopqrstuvwxyz')\n",
    "        # 广度优先遍历建立字典word_dict，value是key的前一个单词的列表      \n",
    "        cur_word_set={beginWord}\n",
    "        word_dict={}\n",
    "        flag=False\n",
    "        while cur_word_set:\n",
    "            match_set=set()\n",
    "            for word in cur_word_set:\n",
    "               for i in range(size):\n",
    "                  for j in letters:\n",
    "                    if word[i]==j:\n",
    "                        continue\n",
    "                    w=word[:i]+j+word[i+1:]\n",
    "                    if w in wordSet:\n",
    "                        match_set.add(w)\n",
    "                        if w not in word_dict:\n",
    "                            word_dict[w]=[]\n",
    "                        word_dict[w].append(word)\n",
    "                        if w==endWord:\n",
    "                            flag=True\n",
    "            for i in match_set:\n",
    "                wordSet.remove(i)\n",
    "            cur_word_set=match_set\n",
    "            if flag:break\n",
    "\n",
    "        #在字典中深度优先遍历，找出所有最短路径\n",
    "        ans=[]\n",
    "        if not flag:\n",
    "            return ans\n",
    "        oneans=[endWord]\n",
    "        def dfs(word):\n",
    "            if word==beginWord:\n",
    "                ans.append(oneans[::-1])\n",
    "            else:\n",
    "                for w in word_dict[word]:\n",
    "                    oneans.append(w)\n",
    "                    dfs(w)\n",
    "                    oneans.pop()\n",
    "        dfs(endWord)\n",
    "        return ans    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        ans = []\n",
    "        if endWord not in wordList:\n",
    "            return ans\n",
    "        size = len(beginWord)\n",
    "        cur_word_set = {beginWord}\n",
    "        ws = set(wordList)\n",
    "        # 用于控制bfs结束\n",
    "        flag = False\n",
    "        if beginWord in ws:\n",
    "             ws.remove(beginWord)\n",
    "        tmp = list('abcdefghijklmnopqrstuvwxyz')\n",
    "        # key为当前单词，value为能到达该单词（bfs搜索）的单词列表，即该单词的parent\n",
    "        word_dict = {}\n",
    "        # bfs\n",
    "        while cur_word_set:\n",
    "            # 该次bfs匹配到的单词\n",
    "            match_set = set()\n",
    "            for cur in cur_word_set:\n",
    "                for i in range(size):\n",
    "                    for j in tmp:\n",
    "                        if cur[i] == j:\n",
    "                            continue\n",
    "                        word = cur[:i] + j + cur[i + 1:]\n",
    "                        # word在单词列表中\n",
    "                        if word in ws:\n",
    "                            # 匹配加入该单词\n",
    "                            match_set.add(word)\n",
    "                            # 为该单词维护parent\n",
    "                            if word not in word_dict:\n",
    "                                word_dict[word] = []\n",
    "                            word_dict[word].append(cur)\n",
    "                            # 到达终点 bfs结束\n",
    "                            if word == endWord:\n",
    "                                flag = True\n",
    "            # 该次bfs结束，剔除掉匹配到的单词\n",
    "            for el in match_set:\n",
    "                ws.remove(el)\n",
    "            # 下次bfs的parent\n",
    "            cur_word_set = match_set\n",
    "            if flag: break\n",
    "        # 完成bfs开始dfs,通过endword反向找parent,直到找到beginword\n",
    "\n",
    "        # 没有匹到endword,直接结束\n",
    "        if not flag: return ans\n",
    "        result = [endWord]\n",
    "        def dfs(cur_word):\n",
    "            if cur_word == beginWord:\n",
    "                ans.append(result[::-1])\n",
    "                return\n",
    "            for el in word_dict[cur_word]:\n",
    "                result.append(el)\n",
    "                dfs(el)\n",
    "                result.pop()\n",
    "\n",
    "        dfs(endWord)\n",
    "        return ans\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        res = []\n",
    "        # 将wordList存入字典，以便快速判断单词是否在wordList中\n",
    "        word_set = set(wordList)\n",
    "        # 如果endWord不在字典中，直接返回空结果\n",
    "        if endWord not in word_set:\n",
    "            return res\n",
    "        # 删除beginWord以避免后面的冗余搜索\n",
    "        word_set.discard(beginWord)\n",
    "\n",
    "        # 广度优先搜索建图\n",
    "        # 记录扩展出的单词是在第几次扩展的时候得到的，key：单词，value：在广度优先搜索的第几层\n",
    "        steps = {beginWord: 0}\n",
    "        # 记录了单词是从哪些单词扩展而来，key：单词，value：单词列表，这些单词可以变换到 key ，它们是一对多关系\n",
    "        from_dict = {beginWord: []}\n",
    "        step = 1\n",
    "        found = False\n",
    "        word_len = len(beginWord)\n",
    "        queue = [beginWord]\n",
    "\n",
    "        while queue:\n",
    "            size = len(queue)\n",
    "            for _ in range(size):\n",
    "                curr_word = queue.pop(0)\n",
    "                char_array = list(curr_word)\n",
    "                # 将每一位替换成 26 个小写英文字母\n",
    "                for j in range(word_len):\n",
    "                    origin = char_array[j]\n",
    "                    for c in range(ord('a'), ord('z') + 1):\n",
    "                        char_array[j] = chr(c)\n",
    "                        next_word = ''.join(char_array)\n",
    "                        if next_word in steps and step == steps[next_word]:\n",
    "                            from_dict[next_word].append(curr_word)\n",
    "                        if next_word not in word_set:\n",
    "                            continue\n",
    "                        # 如果从一个单词扩展出来的单词以前遍历过，距离一定更远\n",
    "                        # 为了避免搜索到已经遍历到且距离更远的单词，需要将它从word_set中删除\n",
    "                        word_set.remove(next_word)\n",
    "                        # 这一层扩展出的单词进入队列\n",
    "                        queue.append(next_word)\n",
    "                        # 记录 next_word 从 curr_word 而来\n",
    "                        from_dict.setdefault(next_word, []).append(curr_word)\n",
    "                        # 记录 next_word 的 step\n",
    "                        steps[next_word] = step\n",
    "                        if next_word == endWord:\n",
    "                            found = True\n",
    "                    char_array[j] = origin\n",
    "            step += 1\n",
    "            if found:\n",
    "                break\n",
    "\n",
    "        # 第 2 步：回溯找到所有解\n",
    "        if found:\n",
    "            path = [endWord]\n",
    "            self.backtrack(from_dict, path, beginWord, endWord, res)\n",
    "        return res\n",
    "\n",
    "    def backtrack(self, from_dict, path, begin_word, cur, res):\n",
    "        if cur == begin_word:\n",
    "            res.append(list(path))\n",
    "            return\n",
    "        for precursor in from_dict[cur]:\n",
    "            path.insert(0, precursor)\n",
    "            self.backtrack(from_dict, path, begin_word, precursor, res)\n",
    "            path.pop(0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "        \n",
    "        if beginWord not in wordList:\n",
    "            wordList.append(beginWord)\n",
    "\n",
    "        begin = wordList.index(beginWord)\n",
    "        end = wordList.index(endWord)\n",
    "        n = len(wordList)\n",
    "        edges = [[] for _ in range(n)]\n",
    "\n",
    "        for i in range(n):\n",
    "            for j in range(i + 1, n):\n",
    "                diff = sum(1 for k in range(len(wordList[i])) if wordList[i][k] != wordList[j][k])\n",
    "                if diff == 1:\n",
    "                    edges[i].append(j)\n",
    "                    edges[j].append(i)\n",
    "        \n",
    "\n",
    "        vis = [False for _ in range(n)]\n",
    "        vis[begin] = True\n",
    "        found = False\n",
    "\n",
    "        q = deque([begin])\n",
    "        levelCur = 0\n",
    "        levels = [0] * n\n",
    "\n",
    "        target = 0\n",
    "        while len(q):\n",
    "            length = len(q)\n",
    "            levelCur += 1\n",
    "            for _ in range(length):\n",
    "                u = q.popleft()\n",
    "                # print(wordList[u])\n",
    "                if u == end:\n",
    "                    found = True\n",
    "                    target = levelCur - 1\n",
    "                    break\n",
    "                \n",
    "                for to in edges[u]:\n",
    "                    if not vis[to]:         \n",
    "                        vis[to] = True  \n",
    "                        q.append(to)\n",
    "                        levels[to] = levelCur\n",
    "\n",
    "        res = []\n",
    "\n",
    "\n",
    "        # print(levelMap)\n",
    "\n",
    "        def dfs(u, path, levelCur):\n",
    "            \n",
    "            if u == begin:\n",
    "                res.append([wordList[i] for i in path[::-1]])\n",
    "                return \n",
    "\n",
    "            for to in edges[u]:\n",
    "                if levels[to] == levelCur:\n",
    "                    dfs(to, path + [to], levelCur - 1)\n",
    "\n",
    "        \n",
    "        dfs(end, [end], target - 1)\n",
    "\n",
    "        return res\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        s = 'abcdefghijklmnopqrstuvwxyz'\n",
    "        l = len(beginWord)\n",
    "        wordSet = set([word for word in wordList if len(word)==l])\n",
    "        wordSet.discard(beginWord)\n",
    "        if endWord not in wordSet:\n",
    "            return []\n",
    "        \n",
    "        Q = deque([(beginWord,1)])\n",
    "        word_link = dict()\n",
    "        minDeep = None\n",
    "        curDeep = 1\n",
    "        nextWords = set()\n",
    "        while Q:\n",
    "            word, deep = Q.pop()\n",
    "            if minDeep and curDeep == minDeep:\n",
    "                break\n",
    "            if curDeep < deep:\n",
    "                curDeep = deep\n",
    "                nextWords = set()\n",
    "            for i in range(l):\n",
    "                for c in s:\n",
    "                    nextWord = word[:i] + c + word[i+1:]\n",
    "                    if nextWord == endWord:\n",
    "                        if minDeep is None:\n",
    "                            minDeep = deep+1\n",
    "                    if nextWord in nextWords:\n",
    "                        word_link[nextWord].append(word)\n",
    "                    elif nextWord in wordSet:\n",
    "                        word_link[nextWord] = [word]\n",
    "                        nextWords.add(nextWord)\n",
    "                        wordSet.remove(nextWord)\n",
    "                        Q.appendleft((nextWord, deep+1))\n",
    "        if endWord not in word_link:\n",
    "            return []\n",
    "        ress = []\n",
    "        def dfs(word, res):\n",
    "            res.append(word)\n",
    "            if word == beginWord:\n",
    "                ress.append(res[::-1])\n",
    "            else:\n",
    "                for i in word_link[word]:\n",
    "                    dfs(i, res[:])\n",
    "        dfs(endWord, [])\n",
    "        return ress\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "        \n",
    "        if beginWord not in wordList:\n",
    "            wordList.append(beginWord)\n",
    "\n",
    "        begin = wordList.index(beginWord)\n",
    "        end = wordList.index(endWord)\n",
    "        n = len(wordList)\n",
    "        edges = [[] for _ in range(n)]\n",
    "\n",
    "        for i in range(n):\n",
    "            for j in range(i + 1, n):\n",
    "                diff = sum(1 for k in range(len(wordList[i])) if wordList[i][k] != wordList[j][k])\n",
    "                if diff == 1:\n",
    "                    edges[i].append(j)\n",
    "                    edges[j].append(i)\n",
    "        \n",
    "\n",
    "        vis = [False for _ in range(n)]\n",
    "        vis[begin] = True\n",
    "        found = False\n",
    "\n",
    "        q = deque([begin])\n",
    "        levelCur = 0\n",
    "        levels = [0] * n\n",
    "\n",
    "        target = 0\n",
    "        while len(q):\n",
    "            length = len(q)\n",
    "            levelCur += 1\n",
    "            for _ in range(length):\n",
    "                u = q.popleft()\n",
    "                # print(wordList[u])\n",
    "                if u == end:\n",
    "                    found = True\n",
    "                    target = levelCur - 1\n",
    "                    break\n",
    "                \n",
    "                for to in edges[u]:\n",
    "                    if not vis[to]:         \n",
    "                        vis[to] = True  \n",
    "                        q.append(to)\n",
    "                        levels[to] = levelCur\n",
    "\n",
    "        res = []\n",
    "\n",
    "\n",
    "        # print(levelMap)\n",
    "\n",
    "        def dfs(u, path, levelCur):\n",
    "            \n",
    "            if u == begin:\n",
    "                res.append([wordList[i] for i in path[::-1]])\n",
    "                return \n",
    "\n",
    "            for to in edges[u]:\n",
    "                if levels[to] == levelCur:\n",
    "                    dfs(to, path + [to], levelCur - 1)\n",
    "\n",
    "        \n",
    "        dfs(end, [end], target - 1)\n",
    "\n",
    "        return res\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        ans = []\n",
    "        if endWord not in wordList:\n",
    "            return ans\n",
    "        size = len(beginWord)\n",
    "        cur_word_set = {beginWord}\n",
    "        ws = set(wordList)\n",
    "        # 用于控制bfs结束\n",
    "        flag = False\n",
    "        if beginWord in ws:\n",
    "             ws.remove(beginWord)\n",
    "        tmp = list('abcdefghijklmnopqrstuvwxyz')\n",
    "        # key为当前单词，value为能到达该单词（bfs搜索）的单词列表，即该单词的parent\n",
    "        word_dict = {}\n",
    "        # bfs\n",
    "        while cur_word_set:\n",
    "            # 该次bfs匹配到的单词\n",
    "            match_set = set()\n",
    "            for cur in cur_word_set:\n",
    "                for i in range(size):\n",
    "                    for j in tmp:\n",
    "                        if cur[i] == j:\n",
    "                            continue\n",
    "                        word = cur[:i] + j + cur[i + 1:]\n",
    "                        # word在单词列表中\n",
    "                        if word in ws:\n",
    "                            # 匹配加入该单词\n",
    "                            match_set.add(word)\n",
    "                            # 为该单词维护parent\n",
    "                            if word not in word_dict:\n",
    "                                word_dict[word] = []\n",
    "                            word_dict[word].append(cur)\n",
    "                            # 到达终点 bfs结束\n",
    "                            if word == endWord:\n",
    "                                flag = True\n",
    "            # 该次bfs结束，剔除掉匹配到的单词\n",
    "            for el in match_set:\n",
    "                ws.remove(el)\n",
    "            # 下次bfs的parent\n",
    "            cur_word_set = match_set\n",
    "            if flag: break\n",
    "        # 完成bfs开始dfs,通过endword反向找parent,直到找到beginword\n",
    "\n",
    "        # 没有匹到endword,直接结束\n",
    "        if not flag: return ans\n",
    "        result = [endWord]\n",
    "        def dfs(cur_word):\n",
    "            if cur_word == beginWord:\n",
    "                ans.append(result[::-1])\n",
    "                return\n",
    "            for el in word_dict[cur_word]:\n",
    "                result.append(el)\n",
    "                dfs(el)\n",
    "                result.pop()\n",
    "\n",
    "        dfs(endWord)\n",
    "        return ans\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        distance={beginWord:0}\n",
    "        res=[]\n",
    "        wordList=set(wordList)\n",
    "        if endWord not in wordList:\n",
    "            return res\n",
    "\n",
    "            \n",
    "        def bfs(beginWord):\n",
    "            q=deque([beginWord])\n",
    "            while q:\n",
    "                node=q.popleft()\n",
    "                for xx in range(len(node)):\n",
    "                    for i in range(97,123):\n",
    "                        word=node[:xx]+chr(i)+node[xx+1:]\n",
    "                        if word in wordList and word not in distance:\n",
    "                            distance[word]=distance[node]+1\n",
    "                            if word==endWord:\n",
    "                                return\n",
    "                            q.append(word)\n",
    "        bfs(beginWord)\n",
    "        path=[endWord]\n",
    "        def dfs(root):\n",
    "            if root==beginWord:\n",
    "                res.append(path[::-1])\n",
    "            else:\n",
    "                for xx in range(len(root)):\n",
    "                    for i in range(97,123):\n",
    "                        word=root[:xx]+chr(i)+root[xx+1:]\n",
    "                        if word in distance and distance[root]==distance[word]+1:\n",
    "                            path.append(word)\n",
    "                            dfs(word)\n",
    "                            path.pop()\n",
    "        dfs(endWord)\n",
    "        return res\n",
    "\n",
    "            \n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "\n",
    "        word_set = set(wordList)\n",
    "        word_set.discard(beginWord)\n",
    "\n",
    "        from_dict = {beginWord: []}\n",
    "        steps = {}\n",
    "        step = 1\n",
    "        found = False\n",
    "        queen = [beginWord]\n",
    "\n",
    "        while queen:\n",
    "            for _ in range(len(queen)):\n",
    "                curr_word = queen.pop(0)\n",
    "                curr_word_ls = list(curr_word)\n",
    "                for i in range(len(curr_word_ls)):\n",
    "                    origin_char = curr_word_ls[i]\n",
    "                    for c in range(ord('a'), ord('z') + 1):\n",
    "                        curr_word_ls[i] = chr(c)\n",
    "                        next_word = ''.join(curr_word_ls)\n",
    "\n",
    "                        if next_word in steps and steps[next_word] == step:\n",
    "                            from_dict[next_word].append(curr_word)\n",
    "\n",
    "                        if next_word not in word_set:\n",
    "                            continue\n",
    "\n",
    "                        word_set.remove(next_word)\n",
    "                        steps[next_word] = step\n",
    "                        from_dict.setdefault(next_word, []).append(curr_word)\n",
    "                        queen.append(next_word)\n",
    "\n",
    "                        if next_word == endWord:\n",
    "                            found = True\n",
    "\n",
    "                    curr_word_ls[i] = origin_char\n",
    "\n",
    "            step += 1\n",
    "\n",
    "            if found:\n",
    "                break\n",
    "\n",
    "        com = [endWord]\n",
    "        coms = []\n",
    "\n",
    "        def backtrack(dict_, curr, start):\n",
    "            if curr == start:\n",
    "                coms.append(com[::-1])\n",
    "                return\n",
    "            for _ in dict_[curr]:\n",
    "                com.append(_)\n",
    "                backtrack(dict_, _, start)\n",
    "                com.pop()\n",
    "        if found:\n",
    "            backtrack(from_dict, endWord, beginWord)\n",
    "        return coms"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        wordList.append(beginWord)\n",
    "        ### 构建具有邻接关系的桶，邻接关系指只有一个字母不同，用_代替\n",
    "        buckets = defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(beginWord)):\n",
    "                match = word[:i] + '_' + word[i+1:]\n",
    "                buckets[match].append(word)\n",
    "        ##### BFS遍历\n",
    "        preWords = defaultdict(list)  # 前溯词列表\n",
    "        toSeen = deque([(beginWord, 1)])  # 待遍历词及深度\n",
    "        beFound = {beginWord:1}  # 已探测词列表，单词和层数（最短路劲）\n",
    "        while toSeen:\n",
    "            curWord, level = toSeen.popleft()\n",
    "            for i in range(len(beginWord)):\n",
    "                match = curWord[:i] + '_' + curWord[i+1:]\n",
    "                for word in buckets[match]:\n",
    "                    if word not in beFound:\n",
    "                        beFound[word] = level+1\n",
    "                        toSeen.append((word, level+1))\n",
    "                    if beFound[word] == level+1:  \n",
    "                        # 当前深度等于该词首次遍历深度，则仍应加入前溯词列表\n",
    "                        preWords[word].append(curWord)\n",
    "            if endWord in beFound and level+1 > beFound[endWord]:  \n",
    "                # 已搜索到目标词，且完成当前层遍历\n",
    "                break\n",
    "        #### 列表推导式输出结果\n",
    "        if endWord in beFound:\n",
    "            res = [[endWord]]\n",
    "            while res[0][0] != beginWord:\n",
    "                res = [[word] + r for r in res for word in preWords[r[0]]] \n",
    "            return res\n",
    "        else:\n",
    "            return []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        s = 'abcdefghijklmnopqrstuvwxyz'\n",
    "        l = len(beginWord)\n",
    "        wordSet = set([word for word in wordList if len(word)==l])\n",
    "        wordSet.discard(beginWord)\n",
    "        if endWord not in wordSet:\n",
    "            return []\n",
    "        \n",
    "        Q = deque([(beginWord,1)])\n",
    "        word_link = {beginWord:None}\n",
    "        minDeep = None\n",
    "        curDeep = 1\n",
    "        nextWords = set()\n",
    "        while Q:\n",
    "            word, deep = Q.pop()\n",
    "            if minDeep and curDeep == minDeep:\n",
    "                break\n",
    "            if curDeep < deep:\n",
    "                curDeep = deep\n",
    "                nextWords = set()\n",
    "            for i in range(l):\n",
    "                for c in s:\n",
    "                    nextWord = word[:i] + c + word[i+1:]\n",
    "                    if nextWord == endWord:\n",
    "                        if minDeep is None:\n",
    "                            minDeep = deep+1\n",
    "                    if nextWord in nextWords:\n",
    "                        word_link[nextWord].append(word)\n",
    "                    elif nextWord in wordSet:\n",
    "                        word_link[nextWord] = [word]\n",
    "                        nextWords.add(nextWord)\n",
    "                        wordSet.remove(nextWord)\n",
    "                        Q.appendleft((nextWord, deep+1))\n",
    "        if endWord not in word_link:\n",
    "            return []\n",
    "        ress = []\n",
    "        def dfs(word, res):\n",
    "            res.append(word)\n",
    "            if word_link[word] is None:\n",
    "                return ress.append(res[::-1])\n",
    "            for i in word_link[word]:\n",
    "                dfs(i, res[:])\n",
    "        dfs(endWord, [])\n",
    "        return ress\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import deque\n",
    "class Solution:\n",
    "    def distance(self, word1, word2):\n",
    "        if word1 == word2:\n",
    "            return 0\n",
    "        result = 0\n",
    "        for c1, c2 in zip(word1, word2):\n",
    "            if c1 != c2:\n",
    "                result += 1\n",
    "        return result\n",
    "\n",
    "    def get_result(self, word_dict, beginWord, endWord, cur, temps=None):\n",
    "        if not temps:\n",
    "            temps = [beginWord]\n",
    "        if temps and temps[-1] == endWord:\n",
    "            self.results.append(temps.copy())\n",
    "            return\n",
    "        # print(cur, word_dict.get(cur), temps)\n",
    "        if cur in word_dict:\n",
    "            for word in word_dict.get(cur):\n",
    "                temps.append(word)\n",
    "                self.get_result(word_dict, beginWord, endWord, word, temps)\n",
    "                temps.pop()\n",
    "\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        self.results = []\n",
    "        word_set = set(wordList)\n",
    "        if endWord not in word_set:\n",
    "            return self.results\n",
    "        word_set.remove(endWord)\n",
    "        word_set.add(beginWord)\n",
    "        self.parent_tree = {}\n",
    "        word_que = deque()\n",
    "        word_que.append(endWord)\n",
    "        temp_set = set()\n",
    "        while word_que:\n",
    "            flag = False\n",
    "            temp_set.clear()\n",
    "            for i in range(len(word_que)):\n",
    "                cur = word_que.popleft()\n",
    "                if cur in word_set:\n",
    "                    word_set.remove(cur)\n",
    "                for word in word_set:\n",
    "                    if self.distance(cur, word) == 1:\n",
    "                        if word == beginWord:\n",
    "                            flag = True\n",
    "                        if word in self.parent_tree:\n",
    "                            self.parent_tree[word].add(cur)\n",
    "                        else:\n",
    "                            self.parent_tree[word] = {cur}\n",
    "                        temp_set.add(word)\n",
    "            for temp in tuple(temp_set):\n",
    "                word_set.remove(temp)\n",
    "                word_que.append(temp)\n",
    "            if flag == True:\n",
    "                break\n",
    "        if self.parent_tree:\n",
    "            self.get_result(self.parent_tree, beginWord, endWord, beginWord)\n",
    "        # [print(x) for x in self.parent_tree.items()]\n",
    "        return self.results\n",
    "\n",
    "# class tireTree:\n",
    "#     def __init__(self, val=None, parent=None, children=None):\n",
    "#         self.val = val\n",
    "#         self.parent = parent\n",
    "#         self.children = children if children else set()\n",
    "# from collections import deque\n",
    "# class Solution:\n",
    "#     def distance(self, word1, word2):\n",
    "#         if word1 == word2:\n",
    "#             return 0\n",
    "#         result = 0\n",
    "#         for c1, c2 in zip(word1, word2):\n",
    "#             if c1 != c2:\n",
    "#                 result += 1\n",
    "#         return result\n",
    "\n",
    "#     def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "#         if beginWord == endWord:\n",
    "#             return []\n",
    "#         if endWord not in wordList:\n",
    "#             return []\n",
    "#         self.results = []\n",
    "#         self.cur_len = float('inf')\n",
    "#         self.next_dict = {beginWord:set()}\n",
    "#         self.data_dict = {x:self.distance(x, beginWord) for x in wordList}\n",
    "#         for word1 in wordList:\n",
    "#             if self.distance(beginWord, word1) == 1:\n",
    "#                 self.next_dict[beginWord].add(word1)\n",
    "#         for word1 in wordList:\n",
    "#             self.next_dict[word1] = set()\n",
    "#             for word2 in wordList:\n",
    "#                 if word1 == word2:\n",
    "#                     continue\n",
    "#                 if self.distance(word1, word2) == 1:\n",
    "#                     self.next_dict[word1].add(word2)\n",
    "#         root = tireTree(beginWord)\n",
    "#         word_que = deque()\n",
    "#         word_que.append(root)\n",
    "#         used_set = set()\n",
    "#         temp_set = set()\n",
    "#         success_node_set = set()\n",
    "#         while word_que:\n",
    "#             flag = False\n",
    "#             temp_set.clear()\n",
    "#             for i in range(len(word_que)):\n",
    "#                 cur_node = word_que.popleft()\n",
    "#                 temp_set.add(cur_node.val)\n",
    "#                 for next_word in self.next_dict[cur_node.val]:\n",
    "#                     if next_word not in used_set:\n",
    "#                         new_node = tireTree(next_word, cur_node)\n",
    "#                         if next_word == endWord:\n",
    "#                             success_node_set.add(new_node)\n",
    "#                             flag = True\n",
    "#                         cur_node.children.add(next_word)\n",
    "#                         if next_word not in temp_set:\n",
    "#                             word_que.append(new_node)\n",
    "#             if flag == True:\n",
    "#                 break\n",
    "#             used_set.update(temp_set)\n",
    "#         temps = []\n",
    "#         for node in success_node_set:\n",
    "#             temps.clear()\n",
    "#             while node:\n",
    "#                 temps.append(node.val)\n",
    "#                 node = node.parent\n",
    "#             self.results.append(temps[::-1])\n",
    "#         return self.results\n",
    "\n",
    "# class Solution:\n",
    "#     def distance(self, word1, word2):\n",
    "#         if word1 == word2:\n",
    "#             return 0\n",
    "#         result = 0\n",
    "#         for c1, c2 in zip(word1, word2):\n",
    "#             if c1 != c2:\n",
    "#                 result += 1\n",
    "#         return result\n",
    "#     def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "#         if beginWord == endWord:\n",
    "#             return []\n",
    "#         if endWord not in wordList:\n",
    "#             return []\n",
    "#         self.results = []\n",
    "#         self.cur_len = float('inf')\n",
    "#         self.dis_dict = {(beginWord, x):self.distance(beginWord, x) for x in wordList}\n",
    "#         self.dis_dict.update({(x, beginWord):self.dis_dict[(beginWord, x)] for x in wordList})\n",
    "#         # print(self.dis_dict)\n",
    "#         for word1 in wordList:\n",
    "#             for word2 in wordList:\n",
    "#                 if word1 == word2:\n",
    "#                     continue\n",
    "#                 temp = (word2, word1)\n",
    "#                 if temp in self.dis_dict:\n",
    "#                     self.dis_dict[(word1, word2)] = self.dis_dict[temp]\n",
    "#                     continue\n",
    "#                 self.dis_dict[(word1, word2)] = self.distance(word1, word2)\n",
    "#         self.dis_dict[(beginWord, beginWord)] = 0\n",
    "#         self.dis_dict[(endWord, endWord)] = 0\n",
    "#         # print(self.dis_dict)\n",
    "#         def get_result(temps, remains):\n",
    "#             # print(temps, remains)\n",
    "#             # print(10.1, self.dis_dict[(temps[-1], endWord)])\n",
    "#             if temps[-1] == endWord:\n",
    "#                 if self.cur_len >= len(temps):\n",
    "#                     self.cur_len = len(temps)\n",
    "#                     # print(10.2, temps, self.results)\n",
    "#                     while self.results and len(self.results[-1]) > self.cur_len:\n",
    "#                         self.results.pop()\n",
    "#                     self.results.append(temps.copy())\n",
    "#                 return\n",
    "#             for i in range(len(remains)):\n",
    "#                 temp = remains[i]\n",
    "#                 if temps and temp == temps[-1]:\n",
    "#                     continue\n",
    "#                 if self.dis_dict[(temp, temps[-1])] == 1 and self.dis_dict[(temp, endWord)] <= self.dis_dict[(temps[-1], endWord)]:\n",
    "#                     # print(f'{temp=}')\n",
    "#                     if self.cur_len <= len(temps):\n",
    "#                         return\n",
    "#                     temps.append(temp)\n",
    "#                     get_result(temps, remains[:i] + remains[i+1:])\n",
    "#                     temps.pop()\n",
    "#         get_result([beginWord], wordList)\n",
    "#         return self.results\n",
    "\n",
    "\n",
    "# class tireTree:\n",
    "#     def __init__(self, val=None, parent=None, children=None):\n",
    "#         self.val = val\n",
    "#         self.parent = parent\n",
    "#         self.children = children if children else set()\n",
    "# class Solution:\n",
    "#     def distance_is_one(self, word1, word2):\n",
    "#         if word1 == word2:\n",
    "#             return False\n",
    "#         result = 0\n",
    "#         for c1, c2 in zip(word1, word2):\n",
    "#             if c1 != c2:\n",
    "#                 result += 1\n",
    "#                 if result > 1:\n",
    "#                     break\n",
    "#         if result == 1:\n",
    "#             return True\n",
    "#         return False\n",
    "#     def get_path(self, node, beginWord):\n",
    "#         temps = [beginWord]\n",
    "#         while node:\n",
    "#             temps.append(node.val)\n",
    "#             node = node.parent\n",
    "#         return temps\n",
    "#     def check_in_path(self, root, string):\n",
    "#         while root:\n",
    "#             if root.val == string:\n",
    "#                 return True\n",
    "#             root = root.parent\n",
    "#         return False\n",
    "#     def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "#         if beginWord == endWord:\n",
    "#             return []\n",
    "#         results = []\n",
    "#         source_word_set = set(wordList)\n",
    "#         if not endWord in source_word_set:\n",
    "#             return results\n",
    "#         root = tireTree(endWord)\n",
    "#         stack = [root]\n",
    "#         cur_len = float('inf')\n",
    "#         dis_dict = {(beginWord, x):self.distance_is_one(beginWord, x) for x in wordList}\n",
    "#         while stack:\n",
    "#             cur = stack.pop()\n",
    "#             # print('-'*20, cur.val)\n",
    "#             if self.distance_is_one(beginWord, cur.val):\n",
    "#                 temps = self.get_path(cur, beginWord)\n",
    "#                 if cur_len >= len(temps):\n",
    "#                     cur_len = len(temps)\n",
    "#                     results.append(temps)\n",
    "#             for word1 in wordList:\n",
    "#                 if self.distance_is_one(cur.val, word1) and dis_dict[(beginWord, word1)] <= dis_dict[(beginWord, word1)]:\n",
    "#                     if not self.check_in_path(cur, word1):\n",
    "#                         temp = tireTree(word1, cur)\n",
    "#                         cur.children.add(temp)\n",
    "#                         stack.append(temp)\n",
    "#                         # print(10.2, word1)\n",
    "#         results = [x for x in results if len(x) == cur_len]\n",
    "#         return results\n",
    "\n",
    "\n",
    "# from collections import deque\n",
    "# class tireTree:\n",
    "#     def __init__(self, val=None, parent=None, children=None):\n",
    "#         self.val = val\n",
    "#         self.parent = parent\n",
    "#         self.children = children if children else set()\n",
    "# class Solution:\n",
    "#     def distance_is_one(self, word1, word2):\n",
    "#         if word1 == word2:\n",
    "#             return False\n",
    "#         result = 0\n",
    "#         for c1, c2 in zip(word1, word2):\n",
    "#             if c1 != c2:\n",
    "#                 result += 1\n",
    "#                 if result > 1:\n",
    "#                     break\n",
    "#         if result == 1:\n",
    "#             return True\n",
    "#         return False\n",
    "#     def get_path(self, node, beginWord):\n",
    "#         temps = [beginWord]\n",
    "#         while node:\n",
    "#             temps.append(node.val)\n",
    "#             node = node.parent\n",
    "#         return temps\n",
    "#     def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "#         if beginWord == endWord:\n",
    "#             return []\n",
    "#         results = []\n",
    "#         source_word_set = set(wordList)\n",
    "#         if endWord not in source_word_set:\n",
    "#             return results\n",
    "#         root = tireTree(endWord)\n",
    "#         node_que = deque()\n",
    "#         node_que.append([root, source_word_set])\n",
    "#         cur_len = float('inf')\n",
    "#         while node_que:\n",
    "#             cur, source_word_set = node_que.popleft()\n",
    "#             # print('-'*20, cur.val, source_word_set)\n",
    "#             if self.distance_is_one(beginWord, cur.val):\n",
    "#                 temps = self.get_path(cur, beginWord)\n",
    "#                 if cur_len >= len(temps):\n",
    "#                     cur_len = len(temps)\n",
    "#                     results.append(temps)\n",
    "#             for word1 in tuple(source_word_set):\n",
    "#                 if self.distance_is_one(cur.val, word1):\n",
    "#                     temp = tireTree(word1, cur)\n",
    "#                     source_word_set.remove(word1)\n",
    "#                     cur.children.add(temp)\n",
    "#                     node_que.append([temp, source_word_set.copy()])\n",
    "#                     # print(10.2, word1, source_word_set)\n",
    "#         results = [x for x in results if len(x) == cur_len]\n",
    "#         return results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        # bfs\n",
    "        def check(a, b):\n",
    "            diff = 0\n",
    "            m = len(a)\n",
    "            for i in range(m):\n",
    "                if a[i] != b[i]:\n",
    "                    diff += 1\n",
    "                if diff > 1:\n",
    "                    return False\n",
    "            return diff == 1\n",
    "        wordSet = set(wordList)\n",
    "        if endWord not in wordSet:\n",
    "            return []\n",
    "        cnt = defaultdict(lambda: inf)\n",
    "        pre = defaultdict(list) # 最近cnt下的前驱节点\n",
    "        dq = deque([[beginWord, 0]]) # [word, step]\n",
    "        while dq:\n",
    "            #print(dq)\n",
    "            word, step = dq.popleft()\n",
    "            for nxt in wordList:\n",
    "                if check(word, nxt) is False:\n",
    "                    continue\n",
    "                if cnt[nxt] > step + 1:\n",
    "                    cnt[nxt] = step + 1\n",
    "                    pre[nxt] = [word]\n",
    "                    dq.append([nxt, step + 1])\n",
    "                elif cnt[nxt] == step + 1:\n",
    "                    pre[nxt].append(word)\n",
    "                else:\n",
    "                    pass\n",
    "        #print(cnt)\n",
    "        #print(pre)\n",
    "        if cnt[endWord] == inf:\n",
    "            return []\n",
    "        ans = []\n",
    "        tmp = [endWord]\n",
    "        def dfs(cur):\n",
    "            if cur == beginWord:\n",
    "                ans.append(tmp[::-1])\n",
    "                return\n",
    "            for p in pre[cur]:\n",
    "                tmp.append(p)\n",
    "                dfs(p)\n",
    "                tmp.pop()\n",
    "        dfs(endWord)\n",
    "        return ans\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        ans = []\n",
    "        ws = set(wordList)\n",
    "        letters = 'abcdefghijklmnopqrstuvwxyz'\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "        dist = {}\n",
    "        dist[beginWord] = 0\n",
    "        que = collections.deque()\n",
    "        que.append(beginWord)\n",
    "        def bfs():\n",
    "            while que:\n",
    "                curword = que.popleft()\n",
    "                for i in range(len(curword)):\n",
    "                    for j in letters:\n",
    "                        tmp = curword[:i] + j + curword[i+1:]\n",
    "                        if tmp in wordList and tmp not in dist:\n",
    "                            dist[tmp] = dist[curword] + 1\n",
    "                            if tmp == endWord:\n",
    "                                return\n",
    "                            que.append(tmp)\n",
    "        bfs()\n",
    "        path = [endWord]\n",
    "        def dfs(word):\n",
    "            if word == beginWord:\n",
    "                ans.append(path[::-1])\n",
    "            for i in range(len(word)):\n",
    "                for j in letters:\n",
    "                    tmp = word[:i] + j + word[i+1:]\n",
    "                    if tmp in dist and dist[tmp] == dist[word] - 1:\n",
    "                        path.append(tmp)\n",
    "                        dfs(tmp)\n",
    "                        path.pop()\n",
    "        dfs(endWord)\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        wordList.append(beginWord)\n",
    "        ### 构建具有邻接关系的桶\n",
    "        buckets = defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(beginWord)):\n",
    "                match = word[:i] + '_' + word[i+1:]\n",
    "                buckets[match].append(word)\n",
    "        ##### BFS遍历\n",
    "        preWords = defaultdict(list)  # 前溯词列表\n",
    "        toSeen = deque([(beginWord, 1)])  # 待遍历词及深度\n",
    "        beFound = {beginWord:1}  # 已探测词列表\n",
    "        while toSeen:\n",
    "            curWord, level = toSeen.popleft()\n",
    "            for i in range(len(beginWord)):\n",
    "                match = curWord[:i] + '_' + curWord[i+1:]\n",
    "                for word in buckets[match]:\n",
    "                    if word not in beFound:\n",
    "                        beFound[word] = level+1\n",
    "                        toSeen.append((word, level+1))\n",
    "                    if beFound[word] == level+1:  # 当前深度等于该词首次遍历深度，则仍应加入前溯词列表\n",
    "                        preWords[word].append(curWord)\n",
    "            if endWord in beFound and level+1 > beFound[endWord]:  # 已搜索到目标词，且完成当前层遍历\n",
    "                break\n",
    "        #### 列表推导式输出结果\n",
    "        if endWord in beFound:\n",
    "            res = [[endWord]]\n",
    "            while res[0][0] != beginWord:\n",
    "                res = [[word] + r for r in res for word in preWords[r[0]]] \n",
    "            return res\n",
    "        else:\n",
    "            return []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "\n",
    "        ans = []\n",
    "        word_set = set(wordList)\n",
    "\n",
    "        if endWord not in word_set:\n",
    "            return ans\n",
    "\n",
    "        if beginWord in word_set:\n",
    "            word_set.remove(beginWord)\n",
    "        word_set.remove(endWord)\n",
    "\n",
    "        q1 = {beginWord}\n",
    "        q2 = {endWord}\n",
    "        edges = collections.defaultdict(list)\n",
    "        direction = False\n",
    "        found = False\n",
    "\n",
    "        chars = [chr(j + ord('a')) for j in range(26)]\n",
    "        size = len(beginWord)\n",
    "\n",
    "        while q1:\n",
    "            q = set()\n",
    "            for w in q1:\n",
    "                for i in range(size):\n",
    "                    for char in chars:\n",
    "                        if w[i] == char:\n",
    "                            continue\n",
    "                        s = w[:i] + char + w[i + 1:]\n",
    "                        if s in word_set:\n",
    "                            q.add(s)\n",
    "                            edges[w].append(s) if direction else edges[s].append(w)\n",
    "                        if s in q2:\n",
    "                            edges[w].append(s) if direction else edges[s].append(w)\n",
    "                            found = True\n",
    "\n",
    "            if found:\n",
    "                break\n",
    "            for w in q:\n",
    "                word_set.remove(w)\n",
    "\n",
    "            q1 = q\n",
    "            # if len(q) <= len(q2):\n",
    "            #     q1 = q\n",
    "            # else:\n",
    "            #     direction = not direction\n",
    "            #     q1 = q2\n",
    "            #     q2 = q\n",
    "\n",
    "        if found:\n",
    "            path = [endWord]\n",
    "\n",
    "            def dfs(cur_word):\n",
    "                if cur_word == beginWord:\n",
    "                    ans.append(path[::-1])\n",
    "                    return\n",
    "                for s in edges[cur_word]:\n",
    "                    path.append(s)\n",
    "                    dfs(s)\n",
    "                    path.pop()\n",
    "                return\n",
    "\n",
    "            dfs(endWord)\n",
    "\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        wordList.append(beginWord)\n",
    "        ### 构建具有邻接关系的桶\n",
    "        buckets = defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(beginWord)):\n",
    "                match = word[:i] + '_' + word[i+1:]\n",
    "                buckets[match].append(word)\n",
    "        ##### BFS遍历\n",
    "        preWords = defaultdict(list)  # 前溯词列表\n",
    "        toSeen = deque([(beginWord, 1)])  # 待遍历词及深度\n",
    "        beFound = {beginWord:1}  # 已探测词列表\n",
    "        while toSeen:\n",
    "            curWord, level = toSeen.popleft()\n",
    "            for i in range(len(beginWord)):\n",
    "                match = curWord[:i] + '_' + curWord[i+1:]\n",
    "                for word in buckets[match]:\n",
    "                    if word not in beFound:\n",
    "                        beFound[word] = level+1\n",
    "                        toSeen.append((word, level+1))\n",
    "                    if beFound[word] == level+1:  # 当前深度等于该词首次遍历深度，则仍应加入前溯词列表\n",
    "                        preWords[word].append(curWord)\n",
    "            if endWord in beFound and level+1 > beFound[endWord]:  # 已搜索到目标词，且完成当前层遍历\n",
    "                break\n",
    "        #### 列表推导式输出结果\n",
    "        if endWord in beFound:\n",
    "            res = [[endWord]]\n",
    "            while res[0][0] != beginWord:\n",
    "                res = [[word] + r for r in res for word in preWords[r[0]]] \n",
    "            return res\n",
    "        else:\n",
    "            return []\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        def backtrack(node):\n",
    "            # print(cur)\n",
    "            if node == beginWord:\n",
    "                ret.append(cur[::-1])\n",
    "                return\n",
    "            for e in word_dict[node]:\n",
    "                cur.append(e)\n",
    "                backtrack(e)\n",
    "                cur.pop()\n",
    "\n",
    "        step = defaultdict(lambda: float('inf'))\n",
    "        wl = set(wordList+[beginWord])\n",
    "        visited = defaultdict(lambda: False)\n",
    "        queue = collections.deque([[beginWord, 0]])\n",
    "        word_dict = collections.defaultdict(lambda: set())\n",
    "        # tmp = []\n",
    "        flag = False\n",
    "        k = len(beginWord)\n",
    "        while queue:\n",
    "            match_set = set()\n",
    "            for cur, st in queue:\n",
    "                for i in range(k):\n",
    "                    for j in range(26):\n",
    "                        if cur[i] == chr(j+ord(\"a\")):\n",
    "                            continue\n",
    "                        e = cur[:i]+chr(j+ord(\"a\"))+cur[(i+1):]\n",
    "                        if e in wl and step[e] >= st+1:\n",
    "                            step[e] = st+1\n",
    "                            word_dict[e].add(cur)\n",
    "                            match_set.add((e, st+1))\n",
    "                            if e == endWord: \n",
    "                                flag = True\n",
    "            # for el in match_set:\n",
    "            #     wl.remove(el)\n",
    "            queue = match_set\n",
    "            if flag: break\n",
    "\n",
    "        ret = []\n",
    "        if not flag: return ret\n",
    "        cur = [endWord]\n",
    "        backtrack(endWord)\n",
    "        return ret\n",
    "\n",
    "\n",
    "        \n",
    "        \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        d, res = collections.defaultdict(set), [[endWord]]\n",
    "        for w1 in wordList + [beginWord]:\n",
    "            for w2 in wordList + [beginWord]:\n",
    "                if sum(i!=j for i, j in zip(w1, w2)) == 1:\n",
    "                    d[w1].add(w2)\n",
    "                    d[w2].add(w1)\n",
    "        l, visited, flag = [{beginWord: []}], {beginWord}, True\n",
    "        while flag and l[-1]:\n",
    "            l.append(collections.defaultdict(list))\n",
    "            for w1 in l[-2]:\n",
    "                for w2 in d[w1]:\n",
    "                    if w2 == endWord: flag = False\n",
    "                    if w2 not in visited: l[-1][w2].append(w1)\n",
    "            for w2 in l[-1]: visited.add(w2)\n",
    "        if flag: return []\n",
    "        for d in l[:0:-1]:\n",
    "            tmp = []\n",
    "            for x in res:  \n",
    "                for i in d[x[0]]: tmp.append([i]+x)\n",
    "            res = tmp\n",
    "        return res\n",
    "\n",
    "\n",
    "\n",
    "            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        wordList.append(beginWord)\n",
    "        ### 构建具有邻接关系的桶\n",
    "        buckets = defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(beginWord)):\n",
    "                match = word[:i] + '_' + word[i+1:]\n",
    "                buckets[match].append(word)\n",
    "        ##### BFS遍历\n",
    "        preWords = defaultdict(list)  # 前溯词列表\n",
    "        toSeen = deque([(beginWord, 1)])  # 待遍历词及深度\n",
    "        beFound = {beginWord:1}  # 已探测词列表\n",
    "        while toSeen:\n",
    "            curWord, level = toSeen.popleft()\n",
    "            for i in range(len(beginWord)):\n",
    "                match = curWord[:i] + '_' + curWord[i+1:]\n",
    "                for word in buckets[match]:\n",
    "                    if word not in beFound:\n",
    "                        beFound[word] = level+1\n",
    "                        toSeen.append((word, level+1))\n",
    "                    if beFound[word] == level+1:  # 当前深度等于该词首次遍历深度，则仍应加入前溯词列表\n",
    "                        preWords[word].append(curWord)\n",
    "            if endWord in beFound and level+1 > beFound[endWord]:  # 已搜索到目标词，且完成当前层遍历\n",
    "                break\n",
    "        #### 列表推导式输出结果\n",
    "        if endWord in beFound:\n",
    "            res = [[endWord]]\n",
    "            while res[0][0] != beginWord:\n",
    "                res = [[word] + r for r in res for word in preWords[r[0]]] \n",
    "            return res\n",
    "        else:\n",
    "            return []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        size = len(beginWord)\n",
    "        prefix_dict = defaultdict(list)\n",
    "        preword_dict = defaultdict(set)\n",
    "        for word in wordList:\n",
    "            for i in range(size):\n",
    "                pattern = word[:i] + '*' + word[(i+1):]\n",
    "                prefix_dict[pattern].append(word)\n",
    "        visited = {}\n",
    "        level = 1\n",
    "        visited[beginWord] = 1\n",
    "        queue = deque([beginWord])\n",
    "        while queue:\n",
    "            n = len(queue)\n",
    "            for _ in range(n):\n",
    "                curword = queue.popleft()\n",
    "                # if curword == endWord:\n",
    "                #     return level\n",
    "                for i in range(size):\n",
    "                    tmp = curword[:i] + \"*\" + curword[(i+1):]\n",
    "                    for nxtword in prefix_dict[tmp]:\n",
    "                        if not nxtword in visited:\n",
    "                            queue.append(nxtword)\n",
    "                            visited[nxtword] = level + 1\n",
    "                        if visited[nxtword] == visited[curword] + 1:\n",
    "                            preword_dict[nxtword].add(curword)\n",
    "            if endWord in visited and level + 1 > visited[endWord]:\n",
    "                break\n",
    "            level += 1\n",
    "\n",
    "        print(preword_dict)\n",
    "\n",
    "        if endWord in visited:\n",
    "            res = [[endWord]]\n",
    "            while res[0][0] != beginWord:\n",
    "                res = [[word] + r for r in res for word in preword_dict[r[0]]]\n",
    "            return res\n",
    "        else:\n",
    "            return []\n",
    "        return []\n",
    "\n",
    "        # if endWord in visited:\n",
    "        #     res = [[endWord]]\n",
    "        #     while res[0][0] != beginWord:\n",
    "        #         res = [[word] + r for r in res for word in preword_dict[r[0]]] \n",
    "        #     return res\n",
    "        # else:\n",
    "        #     return []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "def dis1(a,b):\n",
    "    n=0\n",
    "    for i in range(len(a)):\n",
    "        if a[i]!=b[i]:\n",
    "            n+=1\n",
    "            if n>1:\n",
    "                return False\n",
    "    if n==1:\n",
    "        return True\n",
    "    else:\n",
    "        return False\n",
    "\n",
    "def words(bw,ew,wl):\n",
    "    if ew not in wl:\n",
    "        return []\n",
    "    wl=[bw,*wl]\n",
    "    dis1dic={}\n",
    "    sz=len(wl)\n",
    "    for i in range(sz):\n",
    "        for j in range(i+1,sz):\n",
    "            if dis1(wl[i],wl[j]):\n",
    "                if wl[i] not in dis1dic:\n",
    "                    dis1dic[wl[i] ]=[wl[j]]\n",
    "                else:\n",
    "                    dis1dic[wl[i]].append(wl[j])\n",
    "                if wl[j] not in dis1dic:\n",
    "                    dis1dic[wl[j] ]=[wl[i]]\n",
    "                else:\n",
    "                    dis1dic[wl[j]].append(wl[i]) \n",
    "    if bw not in dis1dic:\n",
    "        return []\n",
    "    \n",
    "    beginSearch=[bw]\n",
    "    \n",
    "    def search(beginSearch):\n",
    "        disF={}\n",
    "        sn=1\n",
    "        find=False\n",
    "        searched=set([beginSearch[0]])\n",
    "        returnDic={}\n",
    "        while not find and sn<sz+1:\n",
    "           \n",
    "            tempsearch=set()\n",
    "            for ser in beginSearch:\n",
    "                s=ser\n",
    "                for k in dis1dic[s]:\n",
    "                    if k not in searched:\n",
    "                        if k not in returnDic:  \n",
    "                            returnDic[k]=set([s])\n",
    "                        else:\n",
    "                            returnDic[k].add(s)\n",
    "                        vv=k\n",
    "                        if sn not in disF:\n",
    "                            disF[sn]=set([vv])\n",
    "                        else:\n",
    "                            disF[sn].add(vv)\n",
    "                        if k==ew:\n",
    "                            find=True\n",
    "                        tempsearch.add(k)\n",
    "            #print(disF[sn])\n",
    "            searched=searched|tempsearch\n",
    "            if find:\n",
    "                break\n",
    "            else:\n",
    "                if not sn in disF:\n",
    "                    return []\n",
    "                beginSearch=disF[sn]\n",
    "                sn+=1\n",
    "     \n",
    "        if not find:\n",
    "            return []\n",
    "        #print(disF[sn])\n",
    "        \n",
    "        \n",
    "        result=[[ew]]\n",
    "        while True:\n",
    "            tempr=[]\n",
    "            for r in result:\n",
    "                if (r[-1]) in returnDic:\n",
    "                   # print(returnDic[(r[-1],sn)])\n",
    "                    for k in returnDic[(r[-1])]:\n",
    "                        if k not in r:\n",
    "                            tempr.append([*r,k])   \n",
    "            result=tempr \n",
    "            sn-=1\n",
    "            if sn==0:\n",
    "                break\n",
    "        result=[[*(r[::-1])] for r in result]\n",
    "    \n",
    "        return result\n",
    "    return search(beginSearch)\n",
    "    \n",
    "    \n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        return words(beginWord,endWord,wordList)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        def backtrack(node):\n",
    "            print(cur)\n",
    "            if node == beginWord:\n",
    "                ret.append(cur[::-1])\n",
    "                return\n",
    "            for e in word_dict[node]:\n",
    "                cur.append(e)\n",
    "                backtrack(e)\n",
    "                cur.pop()\n",
    "\n",
    "        wl = set(wordList+[beginWord])\n",
    "        # if beginWord in wl:\n",
    "        #      wl.remove(beginWord)\n",
    "        visited = defaultdict(lambda: False)\n",
    "        queue = collections.deque([beginWord])\n",
    "        word_dict = collections.defaultdict(lambda: set())\n",
    "        # tmp = []\n",
    "        flag = False\n",
    "        while queue:\n",
    "            match_set = set()\n",
    "            for cur in queue:\n",
    "                k = len(cur)\n",
    "                for i in range(k):\n",
    "                    for j in range(26):\n",
    "                        if cur[i] == chr(j+ord(\"a\")):\n",
    "                            continue\n",
    "                        e = cur[:i]+chr(j+ord(\"a\"))+cur[(i+1):]\n",
    "                        if e in wl:\n",
    "                            word_dict[e].add(cur)\n",
    "                            match_set.add(e)\n",
    "                            if e == endWord: \n",
    "                                flag = True\n",
    "            for el in match_set:\n",
    "                wl.remove(el)\n",
    "            queue = match_set\n",
    "            if flag: break\n",
    "\n",
    "        ret = []\n",
    "        if not flag: return ret\n",
    "        cur = [endWord]\n",
    "        backtrack(endWord)\n",
    "        return ret\n",
    "\n",
    "\n",
    "        \n",
    "        \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        wordList.append(beginWord)\n",
    "        buckets=defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(beginWord)):\n",
    "                match = word[:i]+'_'+word[i+1:]\n",
    "                buckets[match].append(word)\n",
    "        prewords=defaultdict(list)\n",
    "        toseen=deque([(beginWord,1)])\n",
    "        befound={beginWord:1}\n",
    "        while toseen:\n",
    "            curword,level=toseen.popleft()\n",
    "            for i in range(len(beginWord)):\n",
    "                match=curword[:i]+'_'+curword[i+1:]\n",
    "                for word in buckets[match]:\n",
    "                    if word not in befound:\n",
    "                        befound[word]=level+1\n",
    "                        toseen.append((word,level+1))\n",
    "                    if befound[word]==level+1:\n",
    "                        prewords[word].append(curword)\n",
    "            if endWord in befound and level+1>befound[endWord]:\n",
    "                break\n",
    "        if endWord in befound:\n",
    "            res=[[endWord]]\n",
    "            while res[0][0]!=beginWord:\n",
    "                res=[[word]+r for r in res for word in prewords[r[0]]]\n",
    "            return res\n",
    "        else:\n",
    "            return []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        wordList.append(beginWord)\n",
    "        ### 构建具有邻接关系的桶\n",
    "        buckets = defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(beginWord)):\n",
    "                match = word[:i] + '_' + word[i+1:]\n",
    "                buckets[match].append(word)\n",
    "        ##### BFS遍历\n",
    "        preWords = defaultdict(list)  # 前溯词列表\n",
    "        toSeen = deque([(beginWord, 1)])  # 待遍历词及深度\n",
    "        beFound = {beginWord:1}  # 已探测词列表\n",
    "        while toSeen:\n",
    "            curWord, level = toSeen.popleft()\n",
    "            for i in range(len(beginWord)):\n",
    "                match = curWord[:i] + '_' + curWord[i+1:]\n",
    "                for word in buckets[match]:\n",
    "                    if word not in beFound:\n",
    "                        beFound[word] = level+1\n",
    "                        toSeen.append((word, level+1))\n",
    "                    if beFound[word] == level+1:  # 当前深度等于该词首次遍历深度，则仍应加入前溯词列表\n",
    "                        preWords[word].append(curWord)\n",
    "            if endWord in beFound and level+1 > beFound[endWord]:  # 已搜索到目标词，且完成当前层遍历\n",
    "                break\n",
    "        #### 列表推导式输出结果\n",
    "        if endWord in beFound:\n",
    "            res = [[endWord]]\n",
    "            while res[0][0] != beginWord:\n",
    "                res = [[word] + r for r in res for word in preWords[r[0]]] \n",
    "            return res\n",
    "        else:\n",
    "            return []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        from collections import defaultdict\n",
    "        wordSet = set(wordList)\n",
    "        if endWord not in wordSet:\n",
    "            return []\n",
    "        \n",
    "        def backtrace(words: set[str], path) -> None:\n",
    "            if not words:\n",
    "                ans.append(path[::-1])\n",
    "                return\n",
    "            for item in words:\n",
    "                path.append(item)\n",
    "                backtrace(convertMap[item], path)\n",
    "                path.pop()\n",
    "\n",
    "        path = []\n",
    "        ans = []\n",
    "        wordLen = len(beginWord)\n",
    "        convertMap = defaultdict(set)\n",
    "        visited = {beginWord : 0}\n",
    "        prevLevel = [beginWord]\n",
    "        isFindMinSeq = False\n",
    "        level = 1\n",
    "        while prevLevel and not isFindMinSeq:\n",
    "            size = len(prevLevel)\n",
    "            for i in range(size):\n",
    "                word = prevLevel.pop(0)\n",
    "                charLst = list(word)\n",
    "                for j in range(wordLen):\n",
    "                    rawChar = charLst[j]\n",
    "                    for k in range(26):\n",
    "                        newChar = chr(ord('a') + k)\n",
    "                        if newChar == rawChar:\n",
    "                            continue\n",
    "                        charLst[j] = newChar\n",
    "                        newWord = ''.join(charLst)\n",
    "                        if newWord in wordSet:\n",
    "                            if newWord == endWord:\n",
    "                                isFindMinSeq = True\n",
    "                            if newWord not in visited:\n",
    "                                prevLevel.append(newWord)\n",
    "                                visited[newWord] = level\n",
    "                                convertMap[newWord].add(word)\n",
    "                            elif visited[newWord] == level:\n",
    "                                convertMap[newWord].add(word)\n",
    "                    charLst[j] = rawChar\n",
    "            level += 1\n",
    "        if isFindMinSeq:\n",
    "            backtrace({endWord}, [])\n",
    "        return ans\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        wordList = list(set(wordList + [beginWord]))\n",
    "        find_idx = {}\n",
    "        for i, j in enumerate(wordList):\n",
    "            find_idx[j] = i\n",
    "        if endWord not in find_idx:\n",
    "            return []\n",
    "        beginCode, endCode = find_idx[beginWord], find_idx[endWord]\n",
    "        n = len(wordList)\n",
    "        g = [set() for _ in range(n)]\n",
    "        m = len(beginWord)\n",
    "        for i, j in enumerate(wordList):\n",
    "            for k in range(m):\n",
    "                for l in range(26):\n",
    "                    if l != ord(j[k]) - ord('a'):\n",
    "                        tar = j[:k] + ascii_lowercase[l] + j[k + 1:]\n",
    "                        if tar in find_idx:\n",
    "                            idx = find_idx[tar]\n",
    "                            g[i].add(idx)\n",
    "                            g[idx].add(i)\n",
    "\n",
    "        def min_dis(start):\n",
    "            dis = [inf] * n\n",
    "            dq = deque([start])\n",
    "            dis[start] = 0\n",
    "            step = 0\n",
    "            while dq:\n",
    "                step += 1\n",
    "                for _ in range(len(dq)):\n",
    "                    a = dq.popleft()\n",
    "                    for nxt in g[a]:\n",
    "                        if dis[nxt] == inf:\n",
    "                            dis[nxt] = step\n",
    "                            dq.append(nxt)\n",
    "            return dis\n",
    "\n",
    "        dis_begin = min_dis(beginCode)\n",
    "        if dis_begin[endCode] == inf:\n",
    "            return []\n",
    "        shortest_dis = dis_begin[endCode]\n",
    "        dis_end = min_dis(endCode)\n",
    "        via_nodes = set()\n",
    "        for i in range(n):\n",
    "            if dis_end[i] + dis_begin[i] == shortest_dis:\n",
    "                via_nodes.add(i)\n",
    "        res = []\n",
    "\n",
    "        def dfs(node, L):\n",
    "            if node == endCode:\n",
    "                res.append(L)\n",
    "                return\n",
    "            for nxt in g[node]:\n",
    "                if nxt in via_nodes and dis_begin[nxt] > dis_begin[node]:\n",
    "                    dfs(nxt, L + [nxt])\n",
    "\n",
    "        dfs(beginCode, [beginCode])\n",
    "        ans = []\n",
    "        for i in res:\n",
    "            tmp = []\n",
    "            for j in i:\n",
    "                tmp.append(wordList[j])\n",
    "            ans.append(tmp)\n",
    "        return ans \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        prefix_d = defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(0,len(word)):\n",
    "                prefix_d[word[0:i]+\"*\"+word[i+1:]].append(word)\n",
    "        \n",
    "        order = {beginWord: []}\n",
    "        queue = deque([beginWord])\n",
    "        temp_q = deque()\n",
    "        go_on = True\n",
    "        end_list = []\n",
    "        \n",
    "        while queue and go_on:  # There is no node even added to temp_q\n",
    "            temp_d = {}\n",
    "            while queue:        # Pop every node on this level\n",
    "                cur = queue.popleft()\n",
    "                for i in range(0, len(cur)):\n",
    "                    for j in prefix_d[cur[0:i]+\"*\"+cur[i+1:]]:\n",
    "                        if j == endWord:\n",
    "                            end_list.append(j)\n",
    "                            go_on = False\n",
    "                        if j not in order:\n",
    "                            if j not in temp_d:\n",
    "                                temp_d[j] = [cur]\n",
    "                                temp_q.append(j)\n",
    "                            else:\n",
    "                                temp_d[j].append(cur)\n",
    "            queue = temp_q\n",
    "            temp_q = deque()\n",
    "            order.update(temp_d)\n",
    "        \n",
    "        ret = []\n",
    "        \n",
    "        # DFS to restore the paths\n",
    "        def dfs(path, node):\n",
    "            path = path + [node]    # add the node(Deepcopy)\n",
    "            if order[node] == []:\n",
    "                ret.append(list(path[::-1]))\n",
    "                return\n",
    "            for i in order[node]:\n",
    "                dfs(path, i)\n",
    "        if endWord in order:\n",
    "            dfs([], endWord)\n",
    "        else:\n",
    "            return []\n",
    "        \n",
    "        return ret"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "\n",
    "        def isnext(w1, w2) :\n",
    "            x = zip(w1,w2)\n",
    "            f = 0\n",
    "            for a,b in x:\n",
    "                if a!=b :\n",
    "                    f +=1\n",
    "                if f >1 :\n",
    "                    return False\n",
    "            return True\n",
    "        def edges() :\n",
    "            for i in wordList :\n",
    "                dic[i] = []\n",
    "            for i,w1 in enumerate(wordList[0:-1]) :\n",
    "                for j,w2 in enumerate(wordList[i+1:]) :\n",
    "                    if isnext(w1,w2) :\n",
    "                        dic[w1].append(w2)\n",
    "                        dic[w2].append(w1)\n",
    "        def dfs() :\n",
    "            ltmp = [[endWord]]\n",
    "            while ltmp[-1][-1] != beginWord :\n",
    "                l4 = []\n",
    "                for l3 in ltmp :\n",
    "                    x = l3[-1] \n",
    "                    y = {wpare[1] for wpare in r2 if wpare[0] == x}\n",
    "                    for yy in y :\n",
    "                        l4.append(l3 + [yy])\n",
    "                    ltmp = l4.copy()\n",
    "            for i in ltmp :\n",
    "                i.reverse()\n",
    "            return ltmp\n",
    "# main \n",
    "        if beginWord == endWord :\n",
    "            return [beginWord,endWord]\n",
    "        if endWord not in set(wordList) :\n",
    "            return []\n",
    "        dic = {}\n",
    "        edges()\n",
    "        ans = []\n",
    "        \n",
    "        l = set() # = { [w , preword] } cur search\n",
    "        r = set() # node explored\n",
    "        r2 = set() # node pare  explored\n",
    "\n",
    "        for i in wordList :\n",
    "            if isnext(beginWord, i) :\n",
    "                l.add((i,beginWord))\n",
    "        while len(l)>0 :\n",
    "            for w in l:\n",
    "                r.add(w[0])\n",
    "                r2.add(w)\n",
    "            if endWord in {w[0] for w in l} :\n",
    "                for w in l :\n",
    "                    r2.add(w)\n",
    "                lr = dfs()\n",
    "                return lr\n",
    "            l2 = set()\n",
    "            for w in l :\n",
    "                for x in dic[w[0]] :\n",
    "                    if x not in r:\n",
    "                        l2.add((x,w[0]))\n",
    "            l = l2.copy()\n",
    "        return []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        # bfs\n",
    "        def check(a, b):\n",
    "            diff = 0\n",
    "            m = len(a)\n",
    "            for i in range(m):\n",
    "                if a[i] != b[i]:\n",
    "                    diff += 1\n",
    "                if diff > 1:\n",
    "                    return False\n",
    "            return diff == 1\n",
    "        wordSet = set(wordList)\n",
    "        if endWord not in wordSet:\n",
    "            return []\n",
    "        cnt = defaultdict(lambda: inf)\n",
    "        pre = defaultdict(list) # 最近cnt下的前驱节点\n",
    "        dq = deque([[beginWord, 0]]) # [word, step]\n",
    "        while dq:\n",
    "            print(dq)\n",
    "            word, step = dq.popleft()\n",
    "            for nxt in wordList:\n",
    "                if check(word, nxt) is False:\n",
    "                    continue\n",
    "                if cnt[nxt] > step + 1:\n",
    "                    cnt[nxt] = step + 1\n",
    "                    pre[nxt] = [word]\n",
    "                    dq.append([nxt, step + 1])\n",
    "                elif cnt[nxt] == step + 1:\n",
    "                    pre[nxt].append(word)\n",
    "                else:\n",
    "                    pass\n",
    "        print(cnt)\n",
    "        print(pre)\n",
    "        if cnt[endWord] == inf:\n",
    "            return []\n",
    "        ans = []\n",
    "        tmp = [endWord]\n",
    "        def dfs(cur):\n",
    "            if cur == beginWord:\n",
    "                ans.append(tmp[::-1])\n",
    "                return\n",
    "            for p in pre[cur]:\n",
    "                tmp.append(p)\n",
    "                dfs(p)\n",
    "                tmp.pop()\n",
    "        dfs(endWord)\n",
    "        return ans\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from typing import List\n",
    "from collections import defaultdict\n",
    "\n",
    "\n",
    "class Solution:    \n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        word_set = set(wordList)\n",
    "        if endWord not in word_set:\n",
    "            return []\n",
    "        \n",
    "        graph = defaultdict(set)\n",
    "        for word in word_set:\n",
    "            for i in range(len(word)):\n",
    "                graph[f'{word[:i]}*{word[i+1:]}'].add(word)\n",
    "        \n",
    "        word_set.discard(beginWord)\n",
    "        word_set.remove(endWord)\n",
    "        q1, q2 = {beginWord}, {endWord}\n",
    "        reversed, mids = False, set()\n",
    "        parent, child = defaultdict(list), defaultdict(list)\n",
    "        while q1:\n",
    "            q = set()\n",
    "            for word in q1:\n",
    "                for i in range(len(word)):\n",
    "                    for next in graph[f'{word[:i]}*{word[i+1:]}'] & q2:\n",
    "                        mids.add(next)\n",
    "                        if reversed:\n",
    "                            child[next].append(word)\n",
    "                        else:\n",
    "                            parent[next].append(word)\n",
    "            if mids:\n",
    "                break\n",
    "\n",
    "            for word in q1:\n",
    "                for i in range(len(word)):\n",
    "                    for next in graph[f'{word[:i]}*{word[i+1:]}'] & word_set:\n",
    "                        q.add(next)\n",
    "                        if reversed:\n",
    "                            child[next].append(word)\n",
    "                        else:\n",
    "                            parent[next].append(word)\n",
    "            for word in q:\n",
    "                word_set.remove(word)\n",
    "            \n",
    "            q1 = q\n",
    "            if len(q1) > len(q2):\n",
    "                q1, q2 = q2, q1\n",
    "                reversed = not reversed\n",
    "        \n",
    "        res = []\n",
    "        if mids:\n",
    "            left_paths = [[mid] for mid in mids]\n",
    "            while left_paths[0][0] != beginWord:\n",
    "                left_paths = [[parent_word] + left_path for left_path in left_paths for parent_word in parent[left_path[0]]]\n",
    "            right_paths = [[mid] for mid in mids]\n",
    "            while right_paths[0][-1] != endWord:\n",
    "                right_paths = [right_path + [child_word] for right_path in right_paths for child_word in child[right_path[-1]]]\n",
    "            for left in left_paths:\n",
    "                for right in right_paths:\n",
    "                    if left[-1] == right[0]:\n",
    "                        res.append(left + right[1:])\n",
    "        return res\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import collections\r\n",
    "from dis import dis\r\n",
    "import string\r\n",
    "\r\n",
    "\r\n",
    "class Solution:\r\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\r\n",
    "        if endWord not in wordList:\r\n",
    "            return []\r\n",
    "        dist = {}\r\n",
    "        dist[beginWord] = 0\r\n",
    "        st = collections.deque()\r\n",
    "        st.append(beginWord)\r\n",
    "        while st:\r\n",
    "            x = st.popleft()\r\n",
    "            for y in [x[:i]+c+x[i+1:] for i in range(len(x)) for c in string.ascii_lowercase]:\r\n",
    "                if y in wordList and y not in dist:\r\n",
    "                    dist[y] = dist[x] + 1\r\n",
    "                    if y == endWord:\r\n",
    "                        continue\r\n",
    "                    st.append(y)\r\n",
    "        path = [endWord]\r\n",
    "        ans = []\r\n",
    "        def bfs(x):\r\n",
    "            if x == beginWord:\r\n",
    "                ans.append(path[::-1])\r\n",
    "            else:\r\n",
    "                for y in [x[:i]+c+x[i+1:] for i in range(len(x)) for c in string.ascii_lowercase]:\r\n",
    "                    if y in dist and dist[x] == dist[y] + 1:\r\n",
    "                        path.append(y)\r\n",
    "                        bfs(y)\r\n",
    "                        path.pop()\r\n",
    "        bfs(endWord)\r\n",
    "        return ans\r\n",
    "\r\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        if all(beginWord != x for x in wordList):\n",
    "            wordList.append(beginWord)\n",
    "        s = set(wordList)\n",
    "        d = defaultdict(lambda :[])\n",
    "        n = len(wordList)\n",
    "        for i in range(n):\n",
    "            for j in range(i+1, n):\n",
    "                x,y = wordList[i], wordList[j]\n",
    "                if len(x)==len(y) and sum([1 for i,j in zip(x,y) if i!=j]) == 1:\n",
    "                    d[i].append(j)\n",
    "                    d[j].append(i)\n",
    "        start = [i for i in range(n) if wordList[i]==beginWord][0]\n",
    "        end = [i for i in range(n) if wordList[i]==endWord]\n",
    "        if len(end) == 0: return []\n",
    "        end = end[0]\n",
    "\n",
    "        vis = [True]*n\n",
    "        q = [(start,1)]\n",
    "        vis[start] = False\n",
    "        tq = []\n",
    "        ans = inf\n",
    "        lv = defaultdict(lambda :set())\n",
    "        while len(q):\n",
    "            while len(q):\n",
    "                x,dis = q.pop(0)\n",
    "                lv[dis].add(wordList[x])\n",
    "                if x == end:\n",
    "                    ans = dis\n",
    "                    q = []\n",
    "                    break\n",
    "\n",
    "                for y in d[x]:\n",
    "                    if vis[y]:\n",
    "                        vis[y] = False\n",
    "                        tq.append((y,dis+1))\n",
    "            q,tq = tq,q\n",
    "        vis = [True]*n\n",
    "\n",
    "        def f(now,dis):\n",
    "            if now == beginWord:\n",
    "                return [[now]]\n",
    "            if dis < 0 or now not in lv[dis]:\n",
    "                return []\n",
    "            res = []\n",
    "            mn = inf\n",
    "            for i in range(len(now)):\n",
    "                for a in \"abcdefghijklmnopqrstuvwxyz\":\n",
    "                    if a==now[i]: continue\n",
    "                    nx = now[:i]+a+now[i+1:]\n",
    "                    if nx not in s: continue\n",
    "                    nx_res = f(nx, dis-1)\n",
    "\n",
    "                    if len(nx_res) and len(nx_res[0]) < mn:\n",
    "                        res = []\n",
    "                        mn = len(nx_res[0])\n",
    "                        for x in nx_res:\n",
    "                            x.append(now)\n",
    "                        res.extend(nx_res)\n",
    "                    elif len(nx_res) and len(nx_res[0]) == mn:\n",
    "                        for x in nx_res:\n",
    "                            x.append(now)\n",
    "                        res.extend(nx_res)\n",
    "            return res\n",
    "\n",
    "        res = f(endWord,ans)\n",
    "        # for x in res:\n",
    "        #     x.reverse()\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        prefix_d = defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(0,len(word)):\n",
    "                prefix_d[word[0:i]+\"*\"+word[i+1:]].append(word)\n",
    "        \n",
    "        order = {beginWord: []}\n",
    "        queue = deque([beginWord])\n",
    "        temp_q = deque()\n",
    "        go_on = True\n",
    "        \n",
    "        while queue and go_on:  # There is no node even added to temp_q\n",
    "            temp_d = {}\n",
    "            while queue:        # Pop every node on this level\n",
    "                cur = queue.popleft()\n",
    "                for i in range(0, len(cur)):\n",
    "                    for j in prefix_d[cur[:i]+\"*\"+cur[i+1:]]:\n",
    "                        if j == endWord:\n",
    "                            go_on = False\n",
    "                        if j not in order:\n",
    "                            if j not in temp_d:\n",
    "                                temp_d[j] = [cur]\n",
    "                                temp_q.append(j)\n",
    "                            else:\n",
    "                                temp_d[j].append(cur)\n",
    "            queue = temp_q\n",
    "            temp_q = deque()\n",
    "            order.update(temp_d)\n",
    "        \n",
    "        ret = []\n",
    "        \n",
    "        # DFS to restore the paths\n",
    "        def dfs(path, node):\n",
    "            path = path + [node]    # add the node(Deepcopy)\n",
    "            if order[node] == []:\n",
    "                ret.append(list(path[::-1]))\n",
    "                return\n",
    "            for i in order[node]:\n",
    "                dfs(path, i)\n",
    "        if endWord in order:\n",
    "            dfs([], endWord)\n",
    "        else:\n",
    "            return []\n",
    "        \n",
    "        return ret"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution(object):\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        # 把wordlist变成字典，方便后序的查询\n",
    "        if not endWord in wordList: return []\n",
    "        wordList.append(beginWord)\n",
    "        wordList = set(wordList)\n",
    "        l = len(beginWord)\n",
    "\n",
    "        # 尝试用桶的思想来处理，提升查询性能，具体的方式是把每个单词的所有可能的变换保存在dict，\n",
    "        # 提升查询速度\n",
    "        wordBuck = {}\n",
    "        for word in wordList:\n",
    "            for i in range(l):\n",
    "                mark = word[:i] + '*' + word[i + 1:]\n",
    "                if not mark in wordBuck:\n",
    "                    wordBuck[mark] = [word]\n",
    "                else:\n",
    "                    wordBuck[mark].append(word)\n",
    "\n",
    "        # BFS\n",
    "        relation, wordLevel, level = {beginWord: ([])}, {0: [beginWord]}, 1\n",
    "        # relation记录每个word和它的前序单词\n",
    "        # wordlevel记录每一层遍历遇到的单词\n",
    "        curWord, tmp, flag = [beginWord], set([]), False\n",
    "        # flag用来标记是否遇到了endword\n",
    "\n",
    "        while curWord:\n",
    "            cur = curWord.pop()\n",
    "            for i in range(l):\n",
    "                mark = cur[:i] + '*' + cur[i + 1:]\n",
    "                curWordList = wordBuck[mark]\n",
    "                wordBuck[mark].remove(cur)\n",
    "                # 得到i位置的相关单词列表\n",
    "                for next in curWordList:\n",
    "                    # 如果遇到终点，则标记True，这一层走完就跳出循环\n",
    "                    if next == endWord: flag = True\n",
    "                    if not next in relation:\n",
    "                        # 第一次遇到该单词，添加到两个list中\n",
    "                        relation[next] = ([cur])\n",
    "                        wordLevel.setdefault(level, []).append(next)\n",
    "                        tmp.add(next)\n",
    "                    else:\n",
    "                        relation[next].append(cur)\n",
    "\n",
    "            # 这一层走完了\n",
    "            if len(curWord) == 0:\n",
    "                if flag == True:\n",
    "                    break\n",
    "                elif len(tmp) == 0:\n",
    "                    return []\n",
    "                else:\n",
    "                    level += 1\n",
    "                    curWord, tmp = list(tmp), set([])\n",
    "\n",
    "        # 处理得到的list，拼接成需要的结果\n",
    "        floor = len(wordLevel)\n",
    "        result = []\n",
    "\n",
    "        def dfs(floor, tmp, preWord):\n",
    "            if floor == 0:\n",
    "                tmp.append(wordLevel[0][0])\n",
    "                tmp.reverse()\n",
    "                nonlocal result\n",
    "                result.append(tmp)\n",
    "                return\n",
    "            for i in wordLevel[floor]:\n",
    "                if i in relation[preWord]:\n",
    "                    dfs(floor - 1, tmp + [i], i)\n",
    "\n",
    "        dfs(floor - 2, [endWord], endWord)\n",
    "\n",
    "        return result\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        def similar(x,y):\n",
    "            diff = 0\n",
    "            for i in range(len(x)):\n",
    "                if x[i] != y[i]:\n",
    "                    diff += 1\n",
    "            return diff == 1   \n",
    "\n",
    "        edge = defaultdict(list)\n",
    "        n = len(wordList)\n",
    "        end = n\n",
    "        for i,x in enumerate(wordList):\n",
    "            if x == endWord:\n",
    "                end = i\n",
    "        if end == n:\n",
    "            return []\n",
    "        for i,x in enumerate(wordList):\n",
    "            if x == endWord:\n",
    "                end = i\n",
    "            if similar(x, beginWord):\n",
    "                edge[-1].append(i)\n",
    "            for j,y in enumerate(wordList):\n",
    "                if similar(x, y):\n",
    "                    edge[i].append(j)\n",
    "        print(edge)\n",
    "        n = len(wordList)\n",
    "        dist = [0] * n\n",
    "        d = defaultdict(list)\n",
    "        ls = [-1]\n",
    "        # print(end)\n",
    "        while dist[end] == 0:\n",
    "            tmp = []\n",
    "            for i in ls:\n",
    "                for j in edge[i]:\n",
    "                    if dist[j] == 0:\n",
    "                        dist[j] = dist[i] + 1\n",
    "                        tmp.append(j)\n",
    "                        d[j].append(i)\n",
    "                    elif dist[j] == dist[i] + 1:\n",
    "                        d[j].append(i)\n",
    "            ls = tmp\n",
    "            if not ls:\n",
    "                break \n",
    "        ans = []\n",
    "        \n",
    "        def dfs(i, tmp):\n",
    "            if i == -1:\n",
    "                tmp.append(beginWord)\n",
    "                ans.append(tmp[::-1])\n",
    "                tmp.pop()\n",
    "            else:\n",
    "                tmp.append(wordList[i])\n",
    "                for j in d[i]:\n",
    "                    dfs(j, tmp)\n",
    "                tmp.pop()\n",
    "        dfs(end, [])\n",
    "        return ans\n",
    "            \n",
    "\n",
    "\n",
    "\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "# from collections import defaultdict, deque\n",
    "\n",
    "# class Solution:\n",
    "#     def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "#         if beginWord not in wordList:\n",
    "#             wordList.append(beginWord)\n",
    "#         if endWord not in wordList:\n",
    "#             return []\n",
    "#         n = len(wordList)\n",
    "#         g = defaultdict(list)\n",
    "#         for i in range(n):\n",
    "#             for j in range(i, n):\n",
    "#                 x, y = wordList[i], wordList[j]\n",
    "#                 if len(x) == len(y):\n",
    "#                     diff_cnt = 0\n",
    "#                     for idx in range(len(x)):\n",
    "#                         if x[idx] != y[idx]:\n",
    "#                             diff_cnt += 1\n",
    "#                     if diff_cnt == 1:\n",
    "#                         g[i].append(j)\n",
    "#                         g[j].append(i)\n",
    "        \n",
    "#         start_idx = wordList.index(beginWord)\n",
    "#         end_idx = wordList.index(endWord)\n",
    "#         seen = set()\n",
    "#         seen.add(start_idx)\n",
    "        \n",
    "#         new_g = defaultdict(list)\n",
    "#         q = deque()\n",
    "#         q.append(start_idx)\n",
    "#         while q:\n",
    "#             new_q = deque()\n",
    "#             while q:\n",
    "#                 node = q.popleft()\n",
    "#                 for nei in g[node]:\n",
    "#                     if nei not in seen:\n",
    "#                         new_g[node].append(nei)\n",
    "#                         if nei not in new_q:\n",
    "#                             new_q.append(nei)\n",
    "#             for node in new_q:\n",
    "#                 seen.add(node)\n",
    "#             q = new_q\n",
    "        \n",
    "#         def dfs(node, end):\n",
    "#             if node == end:\n",
    "#                 return [[node]]\n",
    "#             ans = []\n",
    "#             for nei in new_g[node]:\n",
    "#                 x = dfs(nei, end)\n",
    "#                 if x != []:\n",
    "#                     for route in x:\n",
    "#                         ans.append([node] + route)\n",
    "#             return ans\n",
    "         \n",
    "#         ans = dfs(start_idx, end_idx)\n",
    "#         for ls in ans:\n",
    "#             for i in range(len(ls)):\n",
    "#                 ls[i] = wordList[ls[i]]\n",
    "#         return ans\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        d = defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(word)):\n",
    "                d[word[:i]+\"*\"+word[i+1:]].append(word)\n",
    "\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "\n",
    "        visited1 = defaultdict(list)\n",
    "        q1 = deque([beginWord])\n",
    "        visited1[beginWord] = []\n",
    "\n",
    "        visited2 = defaultdict(list)\n",
    "        q2 = deque([endWord])\n",
    "        visited2[endWord] = []\n",
    "\n",
    "        ans = []\n",
    "        def dfs(v, visited, path, paths):\n",
    "            path.append(v)\n",
    "            if not visited[v]:\n",
    "                if visited is visited1:\n",
    "                    paths.append(path[::-1])\n",
    "                else:\n",
    "                    paths.append(path[:])\n",
    "            for u in visited[v]:\n",
    "                dfs(u, visited, path, paths)\n",
    "            path.pop()\n",
    "\n",
    "        def bfs(q, visited1, visited2, frombegin):\n",
    "            level_visited = defaultdict(list)\n",
    "            for _ in range(len(q)):\n",
    "                u = q.popleft()\n",
    "\n",
    "                for i in range(len(u)):\n",
    "                    for v in d[u[:i]+\"*\"+u[i+1:]]:\n",
    "                        if v in visited2:\n",
    "                            paths1 = []\n",
    "                            paths2 = []\n",
    "                            dfs(u, visited1, [], paths1)\n",
    "                            dfs(v, visited2, [], paths2)\n",
    "                            if not frombegin:\n",
    "                                paths1, paths2 = paths2, paths1\n",
    "                            for a in paths1:\n",
    "                                for b in paths2:\n",
    "                                    ans.append(a+b)\n",
    "                        elif v not in visited1:\n",
    "                            if v not in level_visited:\n",
    "                                q.append(v)\n",
    "                            level_visited[v].append(u)\n",
    "            visited1.update(level_visited)\n",
    "\n",
    "        while q1 and q2 and not ans:\n",
    "            if len(q1) <= len(q2):\n",
    "                bfs(q1, visited1, visited2, True)\n",
    "            else:\n",
    "                bfs(q2, visited2, visited1, False)\n",
    "\n",
    "        return ans\n",
    "        \n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import defaultdict, deque\r\n",
    "from typing import List\r\n",
    "\r\n",
    "\r\n",
    "class Solution:\r\n",
    "    def findLadders(\r\n",
    "        self, beginWord: str, endWord: str, wordList: List[str]\r\n",
    "    ) -> List[List[str]]:\r\n",
    "        adj = defaultdict(list)\r\n",
    "        wordList.append(beginWord)\r\n",
    "        # O(5 * 500) 常数\r\n",
    "        for word in wordList:\r\n",
    "            for j in range(len(word)):\r\n",
    "                pattern = word[:j] + \"*\" + word[j + 1 :]\r\n",
    "                adj[pattern].append(word)\r\n",
    "\r\n",
    "        preWords = defaultdict(list)\r\n",
    "        q = deque([(beginWord, 1)])  # [word, level]\r\n",
    "        visit = {beginWord: 1}\r\n",
    "        while q:\r\n",
    "            curWord, level = q.popleft()\r\n",
    "            for i in range(len(curWord)):\r\n",
    "                pattern = curWord[:i] + \"*\" + curWord[i + 1 :]\r\n",
    "                for nei in adj[pattern]:\r\n",
    "                    if nei not in visit:\r\n",
    "                        q.append((nei, level + 1))\r\n",
    "                        visit[nei] = level + 1\r\n",
    "                    if visit[nei] == level + 1:\r\n",
    "                        preWords[nei].append(curWord)\r\n",
    "\r\n",
    "            if endWord in visit and level + 1 > visit[endWord]:\r\n",
    "                break\r\n",
    "        for k, v in preWords.items():\r\n",
    "            print(k, v)\r\n",
    "        if endWord in visit:\r\n",
    "            res = [[endWord]]\r\n",
    "            while res[0][0] != beginWord:\r\n",
    "                res = [[word] + w for w in res for word in preWords[w[0]]]\r\n",
    "            return res\r\n",
    "        else:\r\n",
    "            return []\r\n",
    "\r\n",
    "\r\n",
    "# print(\r\n",
    "#     Solution().findLadders(\r\n",
    "#         beginWord=\"hit\",\r\n",
    "#         endWord=\"cog\",\r\n",
    "#         wordList=[\"hot\", \"dot\", \"dog\", \"lot\", \"log\", \"cog\"],\r\n",
    "#     )\r\n",
    "# )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import defaultdict\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "\n",
    "        n = len(beginWord)\n",
    "\n",
    "        # 提前构造查询字段，避免比较两个单词是否相邻（会超时）\n",
    "        mp = defaultdict(set)\n",
    "        for word in wordList:\n",
    "            for i in range(n):\n",
    "                key = word[:i] + '_' + word[i + 1:]  # 第i位用下划线替换，同一个key的，属于相邻\n",
    "                mp[key].add(word)\n",
    "\n",
    "        visited = defaultdict(bool)\n",
    "        visited[beginWord] = True\n",
    "\n",
    "        # 记录某个单词是从哪些单词变化而来的\n",
    "        prev_words = defaultdict(set)\n",
    "\n",
    "        # BFS模板代码（类似二叉树BFS遍历的代码）\n",
    "        queue = [beginWord]\n",
    "        find = False\n",
    "        while queue:\n",
    "            tmp = set() # 重要！！！这里其实应该用list，但是list超时，应该是题目用例有问题\n",
    "            for word in queue:\n",
    "                for i in range(n):\n",
    "                    key = word[:i] + '_' + word[i + 1:]\n",
    "                    for neighbour in mp[key]:\n",
    "                        if neighbour == endWord:\n",
    "                            find = True\n",
    "\n",
    "                        # visited是全局的，因为是找最短路径，前几层如果出现过，当前层可以不用了，\n",
    "                        # 否则当前层满足，那之前的层肯定路径更短\n",
    "                        if not visited[neighbour]:\n",
    "                            tmp.add(neighbour)\n",
    "                            prev_words[neighbour].add(word)\n",
    "\n",
    "            for node in tmp:\n",
    "                # 当前层遍历完成之后再标记，因为可能有多条路径经过同一个word\n",
    "                visited[node] = True\n",
    "\n",
    "            queue = tmp\n",
    "\n",
    "            if find:\n",
    "                break\n",
    "\n",
    "        # 再根据target_level查找所有\n",
    "        if not find:\n",
    "            return []\n",
    "\n",
    "        res = []\n",
    "\n",
    "        def dfs(word, path):\n",
    "            if word == beginWord:\n",
    "                res.append(path.copy())\n",
    "                return\n",
    "\n",
    "            for prev in prev_words[word]:\n",
    "                dfs(prev,  [prev] + path)\n",
    "\n",
    "        dfs(endWord, [endWord])\n",
    "        return res\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        len_s = len(beginWord)\n",
    "        wordList.append(beginWord)\n",
    "        word_set = set(wordList)\n",
    "        visited = set()\n",
    "        word_mapping = collections.defaultdict(list)\n",
    "        stack = collections.deque()\n",
    "        _result = []\n",
    "        rresult = []\n",
    "        level = 1\n",
    "        min_level = float(\"inf\")\n",
    "\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "\n",
    "        @functools.lru_cache()\n",
    "        def check(node):\n",
    "            result = []\n",
    "            pp = list(node)\n",
    "            for p in range(len_s):\n",
    "                f = pp[p]\n",
    "                for z in range(97, 123):\n",
    "                    q = chr(z)\n",
    "                    if q != f:\n",
    "                        pp[p] = q\n",
    "                        t = \"\".join(pp)\n",
    "                        if t in word_set:\n",
    "                            result.append(t)\n",
    "                        pp[p] = f\n",
    "            return result\n",
    "\n",
    "        stack.append(endWord)\n",
    "        visited.add(endWord)\n",
    "\n",
    "        while stack:\n",
    "            for i in range(len(stack)):\n",
    "                res = stack.popleft()\n",
    "                if res == beginWord:\n",
    "                    min_level = level\n",
    "                for r in check(res):\n",
    "                    if r not in visited:\n",
    "                        visited.add(r)\n",
    "                        word_mapping[level].append(r)\n",
    "                        stack.append(r)\n",
    "            level += 1\n",
    "        stack.append(beginWord)\n",
    "\n",
    "        def dfs(le, target):\n",
    "            if le == 0:\n",
    "                rresult.append(_result.copy())\n",
    "                return\n",
    "            for b in word_mapping[le]:\n",
    "                if b in check(target):\n",
    "                    _result.append(b)\n",
    "                    dfs(le - 1, b)\n",
    "                    _result.pop()\n",
    "\n",
    "        dfs(min_level - 2, beginWord)\n",
    "\n",
    "        return [[beginWord] + rt + [endWord] for rt in rresult]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import defaultdict\n",
    "from typing import List\n",
    "from collections import deque\n",
    "import string\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        # 先将 wordList 放到哈希表里，便于判断某个单词是否在 wordList 里\n",
    "        word_set = set(wordList)\n",
    "        res = []\n",
    "        if len(word_set) == 0 or endWord not in word_set:\n",
    "            return res\n",
    "\n",
    "        successors = defaultdict(set)\n",
    "        # 第 1 步：使用广度优先遍历得到后继结点列表 successors\n",
    "        # key：字符串，value：广度优先遍历过程中 key 的后继结点列表\n",
    "\n",
    "        found = self.__bfs(beginWord, endWord, word_set, successors)\n",
    "        if not found:\n",
    "            return res\n",
    "        # 第 2 步：基于后继结点列表 successors ，使用回溯算法得到所有最短路径列表\n",
    "        path = [beginWord]\n",
    "        self.__dfs(beginWord, endWord, successors, path, res)\n",
    "        return res\n",
    "\n",
    "    def __bfs(self, beginWord, endWord, word_set, successors):\n",
    "        queue = deque()\n",
    "        queue.append(beginWord)\n",
    "\n",
    "        visited = set()\n",
    "        visited.add(beginWord)\n",
    "\n",
    "        found = False\n",
    "        word_len = len(beginWord)\n",
    "        next_level_visited = set()\n",
    "\n",
    "        while queue:\n",
    "            current_size = len(queue)\n",
    "            for i in range(current_size):\n",
    "                current_word = queue.popleft()\n",
    "                word_list = list(current_word)\n",
    "\n",
    "                for j in range(word_len):\n",
    "                    origin_char = word_list[j]\n",
    "\n",
    "                    for k in string.ascii_lowercase:\n",
    "                        word_list[j] = k\n",
    "                        next_word = ''.join(word_list)\n",
    "\n",
    "                        if next_word in word_set:\n",
    "                            if next_word not in visited:\n",
    "                                if next_word == endWord:\n",
    "                                    found = True\n",
    "\n",
    "                                # 避免下层元素重复加入队列，这里感谢 https://leetcode-cn.com/u/zhao-da-ming/ 优化了这个逻辑\n",
    "                                if next_word not in next_level_visited:\n",
    "                                    next_level_visited.add(next_word)\n",
    "                                    queue.append(next_word)\n",
    "\n",
    "                                successors[current_word].add(next_word)\n",
    "                    word_list[j] = origin_char\n",
    "            if found:\n",
    "                break\n",
    "            # 取两集合全部的元素（并集，等价于将 next_level_visited 里的所有元素添加到 visited 里）\n",
    "            visited |= next_level_visited\n",
    "            next_level_visited.clear()\n",
    "        return found\n",
    "\n",
    "    def __dfs(self, beginWord, endWord, successors, path, res):\n",
    "        if beginWord == endWord:\n",
    "            res.append(path[:])\n",
    "            return\n",
    "\n",
    "        if beginWord not in successors:\n",
    "            return\n",
    "\n",
    "        successor_words = successors[beginWord]\n",
    "        for next_word in successor_words:\n",
    "            path.append(next_word)\n",
    "            self.__dfs(next_word, endWord, successors, path, res)\n",
    "            path.pop()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        def findNeightbors(word):\n",
    "            res = []\n",
    "            for i in range(len(word)):\n",
    "                for j in range(ord('a'), ord('z')+1):\n",
    "                    curr = word[:i]+chr(j)+word[i+1:]\n",
    "                    if chr(j)!=word[i] and curr in wordList:\n",
    "                        res.append(curr)\n",
    "            return res\n",
    "        wordList = set(wordList)\n",
    "        neighbors_record = {}\n",
    "        word_level = {}\n",
    "        res = []\n",
    "        level = 0\n",
    "        queue = [beginWord]\n",
    "        lists = [[beginWord]]\n",
    "        while len(queue)>0:\n",
    "            l = len(queue)\n",
    "            level += 1\n",
    "            for _ in range(l):\n",
    "                curr = queue.pop(0)\n",
    "                curr_list = lists.pop(0)\n",
    "                if curr in neighbors_record:\n",
    "                    nxts = neighbors_record[curr]\n",
    "                else:\n",
    "                    nxts = findNeightbors(curr)\n",
    "                    neighbors_record[curr] = nxts\n",
    "                if curr not in word_level:\n",
    "                    word_level[curr] = level\n",
    "                elif level<=word_level[curr]:\n",
    "                    word_level[curr] = level\n",
    "                else:\n",
    "                    continue\n",
    "                for nxt in nxts:\n",
    "                    if nxt == endWord:\n",
    "                        res.append(curr_list + [nxt])\n",
    "                    queue.append(nxt)\n",
    "                    lists.append(curr_list+[nxt])\n",
    "            if len(res)>0:\n",
    "                break\n",
    "        return res\n",
    "                    \n",
    "\n",
    "                    \n",
    "                \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        len_s = len(beginWord)\n",
    "        wordList.append(beginWord)\n",
    "        word_set = set(wordList)\n",
    "        visited = set()\n",
    "        word_mapping = collections.defaultdict(list)\n",
    "        stack = collections.deque()\n",
    "        _result = []\n",
    "        rresult = []\n",
    "        level = 1\n",
    "        min_level = float(\"inf\")\n",
    "\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "\n",
    "        @functools.lru_cache()\n",
    "        def check(node):\n",
    "            result = []\n",
    "            pp = list(node)\n",
    "            for p in range(len_s):\n",
    "                f = pp[p]\n",
    "                for z in range(97, 123):\n",
    "                    q = chr(z)\n",
    "                    if q != f:\n",
    "                        pp[p] = q\n",
    "                        t = \"\".join(pp)\n",
    "                        if t in word_set:\n",
    "                            result.append(t)\n",
    "                        pp[p] = f\n",
    "            return result\n",
    "\n",
    "        stack.append(endWord)\n",
    "        visited.add(endWord)\n",
    "\n",
    "        while stack:\n",
    "            for i in range(len(stack)):\n",
    "                res = stack.popleft()\n",
    "                if res == beginWord:\n",
    "                    min_level = level\n",
    "                for r in check(res):\n",
    "                    if r not in visited:\n",
    "                        visited.add(r)\n",
    "                        word_mapping[level].append(r)\n",
    "                        stack.append(r)\n",
    "            level += 1\n",
    "        stack.append(beginWord)\n",
    "\n",
    "        def dfs(le, target):\n",
    "            if le == 0:\n",
    "                rresult.append(_result.copy())\n",
    "                return\n",
    "            for b in word_mapping[le]:\n",
    "                if b in check(target):\n",
    "                    _result.append(b)\n",
    "                    dfs(le - 1, b)\n",
    "                    _result.pop()\n",
    "\n",
    "        dfs(min_level - 2, beginWord)\n",
    "\n",
    "        return [[beginWord] + rt + [endWord] for rt in rresult]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        \"\"\"\n",
    "        :type beginWord: str\n",
    "        :type endWord: str\n",
    "        :type wordList: List[str]\n",
    "        :rtype: List[List[str]]\n",
    "        \"\"\"\n",
    "        if not endWord or not beginWord or not wordList or endWord not in wordList \\\n",
    "            or beginWord == endWord:\n",
    "            return []\n",
    "\n",
    "        L = len(beginWord)\n",
    "\n",
    "        # Dictionary to hold combination of words that can be formed,\n",
    "        # from any given word. By changing one letter at a time.\n",
    "        all_combo_dict = collections.defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(L):\n",
    "                all_combo_dict[word[:i] + \"*\" + word[i+1:]].append(word)\n",
    "\n",
    "        # Build graph, bi-BFS\n",
    "        # ans = []\n",
    "        bqueue = collections.deque()\n",
    "        bqueue.append(beginWord)\n",
    "        equeue = collections.deque()\n",
    "        equeue.append(endWord)\n",
    "        bvisited = set([beginWord])\n",
    "        evisited = set([endWord])\n",
    "        rev = False \n",
    "        #graph\n",
    "        parents = collections.defaultdict(set)\n",
    "        found = False \n",
    "        depth = 0\n",
    "        while bqueue and not found:\n",
    "            depth += 1 \n",
    "            length = len(bqueue)\n",
    "            # print(queue)\n",
    "            localVisited = set()\n",
    "            for _ in range(length):\n",
    "                word = bqueue.popleft()\n",
    "                for i in range(L):\n",
    "                    for nextWord in all_combo_dict[word[:i] + \"*\" + word[i+1:]]:\n",
    "                        if nextWord == word:\n",
    "                            continue\n",
    "                        if nextWord not in bvisited:\n",
    "                            if not rev:\n",
    "                                parents[nextWord].add(word)\n",
    "                            else:\n",
    "                                parents[word].add(nextWord)\n",
    "                            if nextWord in evisited:    \n",
    "                                found = True\n",
    "                            localVisited.add(nextWord)\n",
    "                            bqueue.append(nextWord)\n",
    "            bvisited = bvisited.union(localVisited)\n",
    "            bqueue, bvisited, equeue, evisited, rev = equeue, evisited, bqueue, bvisited, not rev\n",
    "        # print(parents)\n",
    "        # print(depth)\n",
    "        # Search path, DFS\n",
    "        ans = []\n",
    "        def dfs(node, path, d):\n",
    "            if d == 0:\n",
    "                if path[-1] == beginWord:\n",
    "                    ans.append(path[::-1])\n",
    "                return \n",
    "            for parent in parents[node]:\n",
    "                path.append(parent)\n",
    "                dfs(parent, path, d-1)\n",
    "                path.pop()\n",
    "        dfs(endWord, [endWord], depth)\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import defaultdict\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "\n",
    "        n = len(beginWord)\n",
    "\n",
    "        # 提前构造查询字段，避免比较两个单词是否相邻（会超时）\n",
    "        mp = defaultdict(set)\n",
    "        for word in wordList:\n",
    "            for i in range(n):\n",
    "                key = word[:i] + '_' + word[i + 1:]  # 第i位用下划线替换，同一个key的，属于相邻\n",
    "                mp[key].add(word)\n",
    "\n",
    "        visited = defaultdict(bool)\n",
    "        visited[beginWord] = True\n",
    "\n",
    "        # 记录某个单词是从哪些单词变化而来的\n",
    "        prev_words = defaultdict(set)\n",
    "\n",
    "        # BFS模板代码（类似二叉树BFS遍历的代码）\n",
    "        queue = [beginWord]\n",
    "        find = False\n",
    "        while queue:\n",
    "            # 重要！！！二叉树BFS遍历，这里用的list\n",
    "            # 这里用set，否则会超时\n",
    "            # 这里用set也没问题，因为同一个点的路径信息已经在上一轮循环的prev_words里面记录了\n",
    "            tmp = set() \n",
    "            for word in queue:\n",
    "                for i in range(n):\n",
    "                    key = word[:i] + '_' + word[i + 1:]\n",
    "                    for neighbour in mp[key]:\n",
    "                        if neighbour == endWord:\n",
    "                            find = True\n",
    "\n",
    "                        # visited是全局的，因为是找最短路径，前几层如果出现过，当前层可以不用了，\n",
    "                        # 否则当前层满足，那之前的层肯定路径更短\n",
    "                        if not visited[neighbour]:\n",
    "                            tmp.add(neighbour)\n",
    "                            prev_words[neighbour].add(word)\n",
    "\n",
    "            for node in tmp:\n",
    "                # 当前层遍历完成之后再标记，因为可能有多条路径经过同一个word\n",
    "                visited[node] = True\n",
    "\n",
    "            queue = tmp\n",
    "\n",
    "            if find:\n",
    "                break\n",
    "\n",
    "        # 再根据target_level查找所有\n",
    "        if not find:\n",
    "            return []\n",
    "\n",
    "        res = []\n",
    "\n",
    "        def dfs(word, path):\n",
    "            if word == beginWord:\n",
    "                res.append(path.copy())\n",
    "                return\n",
    "\n",
    "            for prev in prev_words[word]:\n",
    "                dfs(prev,  [prev] + path)\n",
    "\n",
    "        dfs(endWord, [endWord])\n",
    "        return res\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        len_s = len(beginWord)\n",
    "        wordList.append(beginWord)\n",
    "        word_set = set(wordList)\n",
    "        visited = set()\n",
    "        word_mapping = collections.defaultdict(list)\n",
    "        stack = collections.deque()\n",
    "        _result = []\n",
    "        rresult = []\n",
    "        level = 1\n",
    "        min_level = float(\"inf\")\n",
    "\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "\n",
    "        @functools.lru_cache()\n",
    "        def check(node):\n",
    "            result = []\n",
    "            pp = list(node)\n",
    "            for p in range(len_s):\n",
    "                f = pp[p]\n",
    "                for z in range(97, 123):\n",
    "                    q = chr(z)\n",
    "                    if q != f:\n",
    "                        pp[p] = q\n",
    "                        t = \"\".join(pp)\n",
    "                        if t in word_set:\n",
    "                            result.append(t)\n",
    "                        pp[p] = f\n",
    "            return result\n",
    "\n",
    "        stack.append(endWord)\n",
    "        visited.add(endWord)\n",
    "\n",
    "        while stack:\n",
    "            for i in range(len(stack)):\n",
    "                res = stack.popleft()\n",
    "                if res == beginWord:\n",
    "                    min_level = level\n",
    "                for r in check(res):\n",
    "                    if r not in visited:\n",
    "                        visited.add(r)\n",
    "                        word_mapping[level].append(r)\n",
    "                        stack.append(r)\n",
    "            level += 1\n",
    "        stack.append(beginWord)\n",
    "\n",
    "        def dfs(le, target):\n",
    "            if le == 0:\n",
    "                rresult.append(_result.copy())\n",
    "                return\n",
    "            for b in word_mapping[le]:\n",
    "                if b in check(target):\n",
    "                    _result.append(b)\n",
    "                    dfs(le - 1, b)\n",
    "                    _result.pop()\n",
    "\n",
    "        dfs(min_level - 2, beginWord)\n",
    "\n",
    "        return [[beginWord] + rt + [endWord] for rt in rresult]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import defaultdict\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "\n",
    "        n = len(beginWord)\n",
    "\n",
    "        # 提前构造查询字段，避免比较两个单词是否相邻（会超时）\n",
    "        mp = defaultdict(set)\n",
    "        for word in wordList:\n",
    "            for i in range(n):\n",
    "                key = word[:i] + '_' + word[i + 1:]  # 第i位用下划线替换，同一个key的，属于相邻\n",
    "                mp[key].add(word)\n",
    "\n",
    "        visited = defaultdict(bool)\n",
    "        visited[beginWord] = True\n",
    "\n",
    "        # 记录某个单词是从哪些单词变化而来的\n",
    "        prev_words = defaultdict(set)\n",
    "\n",
    "        # BFS模板代码（类似二叉树BFS遍历的代码）\n",
    "        queue = [beginWord]\n",
    "        find = False\n",
    "        while queue:\n",
    "            tmp = set()\n",
    "            for word in queue:\n",
    "                for i in range(n):\n",
    "                    key = word[:i] + '_' + word[i + 1:]\n",
    "                    for neighbour in mp[key]:\n",
    "                        if neighbour == endWord:\n",
    "                            find = True\n",
    "\n",
    "                        # visited是全局的，因为是找最短路径，前几层如果出现过，当前层可以不用了，\n",
    "                        # 否则当前层满足，那之前的层肯定路径更短\n",
    "                        if not visited[neighbour]:\n",
    "                            tmp.add(neighbour)\n",
    "                            prev_words[neighbour].add(word)\n",
    "\n",
    "            for node in tmp:\n",
    "                visited[node] = True\n",
    "\n",
    "            queue = tmp\n",
    "\n",
    "            if find:\n",
    "                break\n",
    "\n",
    "        # 再根据target_level查找所有\n",
    "        if not find:\n",
    "            return []\n",
    "\n",
    "        res = []\n",
    "\n",
    "        def dfs(word, path):\n",
    "\n",
    "            if word == beginWord:\n",
    "                res.append(path.copy())\n",
    "                return\n",
    "\n",
    "            for prev in prev_words[word]:\n",
    "                dfs(prev,  [prev] + path)\n",
    "\n",
    "        dfs(endWord, [endWord])\n",
    "        return res\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        n = len(beginWord)\n",
    "        wordList = set(wordList)\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "\n",
    "        vis = set()\n",
    "        rel = defaultdict(set)\n",
    "        level = 0\n",
    "        queue = deque([beginWord])\n",
    "        while queue:\n",
    "            level += 1\n",
    "            for i in range(len(queue)):\n",
    "                word = queue.popleft()\n",
    "                if word == endWord:\n",
    "                    queue = []\n",
    "                    break\n",
    "                for i in range(n):\n",
    "                    for char in range(97, 123):\n",
    "                        newword = word[:i] + chr(char) + word[i+1:]\n",
    "                        if newword in wordList and newword != word:\n",
    "                            if newword not in rel[word]:\n",
    "                                rel[newword].add(word)\n",
    "                            if newword not in vis:\n",
    "                                vis.add(newword)\n",
    "                                queue.append(newword)\n",
    "                # print(rel, queue)\n",
    "\n",
    "        ans = []\n",
    "        mark = [endWord]\n",
    "        def DFS(curr, stackLevel):\n",
    "            nonlocal level\n",
    "            if stackLevel > level:\n",
    "                return\n",
    "            if curr == beginWord:\n",
    "                ans.append(mark[::-1].copy())\n",
    "                return\n",
    "            for i in rel[curr]:\n",
    "                mark.append(i)\n",
    "                DFS(i, stackLevel + 1)\n",
    "                mark.pop()\n",
    "        DFS(endWord, 1)\n",
    "        return ans\n",
    "            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from string import ascii_lowercase\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        wordList = set(wordList)\n",
    "        if beginWord not in wordList:\n",
    "            wordList.add(beginWord)\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "\n",
    "        g = defaultdict(set)\n",
    "        for word in wordList:\n",
    "            chars = list(word)\n",
    "            for i, ch1 in enumerate(chars):\n",
    "                for ch2 in ascii_lowercase:\n",
    "                    if ch1 == ch2:\n",
    "                        continue\n",
    "                    chars[i] = ch2\n",
    "                    newword = ''.join(chars)\n",
    "                    if newword in wordList:\n",
    "                        g[word].add(newword)\n",
    "                        g[newword].add(word)\n",
    "                chars[i] = ch1\n",
    "\n",
    "        q1 = deque([beginWord])\n",
    "        q2 = deque([endWord])\n",
    "        vis1 = defaultdict(list)\n",
    "        vis2 = defaultdict(list)\n",
    "        vis1[beginWord].append('')\n",
    "        vis2[endWord].append('')\n",
    "        def bfs(q1, vis1, vis2):\n",
    "            tmp = defaultdict(list)\n",
    "            meet = set()\n",
    "            for _ in range(len(q1)):\n",
    "                word = q1.popleft()\n",
    "                for nxtword in g[word]:\n",
    "                    if nxtword in vis1:\n",
    "                        continue\n",
    "                    if nxtword in vis2:\n",
    "                        meet.add(nxtword)\n",
    "                    if nxtword not in tmp:\n",
    "                        q1.append(nxtword)\n",
    "                    tmp[nxtword].append(word)\n",
    "            vis1.update(tmp)\n",
    "            return meet\n",
    "\n",
    "        while q1 and q2:\n",
    "            if len(q1) <= len(q2):\n",
    "                meet = bfs(q1, vis1, vis2)\n",
    "            else:\n",
    "                meet = bfs(q2, vis2, vis1)\n",
    "            if meet:\n",
    "                break\n",
    "\n",
    "        cur = []\n",
    "        def dfs(word, vis, path):\n",
    "            if not word:\n",
    "                path.append(cur.copy())\n",
    "                return \n",
    "            cur.append(word)\n",
    "            for preword in vis[word]:\n",
    "                dfs(preword, vis, path)\n",
    "            cur.pop()\n",
    "\n",
    "        ans = []\n",
    "        for word in meet:\n",
    "            path1, path2 = [], []\n",
    "            dfs(word, vis1, path1)\n",
    "            dfs(word, vis2, path2)\n",
    "            for p1 in path1:\n",
    "                for p2 in path2:\n",
    "                    path = p1[:0:-1] + p2\n",
    "                    if path[0] != beginWord:\n",
    "                        path = path[::-1]\n",
    "                    ans.append(path)\n",
    "        return ans\n",
    "            \n",
    "\n",
    "            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from functools import lru_cache\n",
    "class Solution(object):\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        def get_next_words(word, word_set):\n",
    "            words = set()\n",
    "            for i in range(len(word)):\n",
    "                for c in 'abcdefghijklmnopqrstuvwxyz':\n",
    "                    next_word = word[:i] + c + word[i + 1:]\n",
    "                    if next_word != word and next_word in word_set:\n",
    "                        words.add(next_word)\n",
    "            return words\n",
    "\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "\n",
    "        word_set = set(wordList)  # 查询提高速度\n",
    "        adjoin_list = defaultdict(set)  # 邻接矩阵,存前向节点，不是后向节点的原因是判重很方便\n",
    "        word_level = defaultdict(set)   # 记录每一层遍历遇到的单词\n",
    "        word_level[0].add(beginWord)\n",
    "        depth = 0\n",
    "        find_flag = False # 是否找到\n",
    "\n",
    "        queue = {beginWord}\n",
    "        while queue:\n",
    "            new_queue = set()\n",
    "            depth += 1\n",
    "            for cur in queue:\n",
    "                for next_word in get_next_words(cur, word_set):\n",
    "                    if next_word == endWord: # 如果遇到终点，则标记True，这一层走完就跳出循环\n",
    "                        find_flag = True\n",
    "                    if next_word not in adjoin_list:\n",
    "                        new_queue.add(next_word)\n",
    "                        word_level[depth].add(next_word)\n",
    "                    adjoin_list[next_word].add(cur)\n",
    "\n",
    "            if find_flag:  # 这一层找到了一定是最短的\n",
    "                break\n",
    "            queue = new_queue\n",
    "\n",
    "        if not find_flag:  # 没找到\n",
    "            return []\n",
    "\n",
    "        # dfs回溯路径\n",
    "        def dfs(depth, tmp, next_word):\n",
    "            if depth == -1:\n",
    "                return [tmp]\n",
    "            res = []\n",
    "            for cur_word in word_level[depth]:\n",
    "                if cur_word in adjoin_list[next_word]:\n",
    "                    res.extend(dfs(depth - 1, [cur_word] + tmp, cur_word))\n",
    "            return res\n",
    "\n",
    "        return dfs(len(word_level) - 2, [endWord], endWord)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        if endWord not in wordList: return []\n",
    "        idx_start, idx_end = 0, 0\n",
    "        if beginWord not in wordList: \n",
    "            wordList.append(beginWord)\n",
    "            idx_start = len(wordList)-1\n",
    "            idx_end = wordList.index(endWord)\n",
    "        else: \n",
    "            idx_start = wordList.index(beginWord)\n",
    "            idx_end = wordList.index(endWord)\n",
    "        N, n, m = 505, len(wordList), len(wordList[0])\n",
    "        dis = [0x3f3f3f3f for i in range(N)]\n",
    "        edges = [[] for i in range(N)]\n",
    "        pre = [[] for i in range(N)]\n",
    "        st, temp, ans = [False] * N, [endWord], []\n",
    "\n",
    "        def check(a: int, b: int) -> bool:\n",
    "            cnt = 0\n",
    "            for i in range(m):\n",
    "                if a[i] != b[i]:\n",
    "                    cnt += 1\n",
    "                    if cnt > 1:\n",
    "                        return False\n",
    "            return True\n",
    "\n",
    "        def djs() -> None:\n",
    "            dis[idx_start] = 0\n",
    "            for i in range(n):\n",
    "                t = -1\n",
    "                for j in range(n):\n",
    "                    if not st[j] and (t == -1 or dis[j] < dis[t]):\n",
    "                        t = j\n",
    "                st[t] = True\n",
    "                for j in edges[t]:\n",
    "                    if dis[j] > dis[t] + 1:\n",
    "                        dis[j] = dis[t] + 1\n",
    "                        pre[j] = [t]\n",
    "                    elif dis[j] == dis[t] + 1:\n",
    "                        pre[j].append(t)\n",
    "        \n",
    "        def dfs(u: int) -> None:\n",
    "            nonlocal ans\n",
    "            if pre[u] == [] and wordList[u] != endWord:\n",
    "                ans.append(list(reversed(temp)))\n",
    "                return\n",
    "            for i in pre[u]:\n",
    "                temp.append(wordList[i])\n",
    "                dfs(i)\n",
    "                temp.pop()\n",
    "\n",
    "        for i in range(n):\n",
    "            for j in range(i+1, n):\n",
    "                if check(wordList[i], wordList[j]):\n",
    "                    edges[i].append(j)\n",
    "                    edges[j].append(i)\n",
    "        djs()\n",
    "        dfs(idx_end)\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import defaultdict\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "\n",
    "        n = len(beginWord)\n",
    "\n",
    "        # 提前构造查询字段，避免比较两个单词是否相邻（会超时）\n",
    "        mp = defaultdict(set)\n",
    "        for word in wordList:\n",
    "            for i in range(n):\n",
    "                key = word[:i] + '_' + word[i + 1:]  # 第i位用下划线替换，同一个key的，属于相邻\n",
    "                mp[key].add(word)\n",
    "\n",
    "        visited = defaultdict(bool)\n",
    "        visited[beginWord] = True\n",
    "\n",
    "        # 记录某个单词是从哪些单词变化而来的\n",
    "        prev_words = defaultdict(set)\n",
    "\n",
    "        # BFS模板代码（类似二叉树BFS遍历的代码）\n",
    "        queue = [beginWord]\n",
    "        find = False\n",
    "        while queue:\n",
    "            # 重要！！！二叉树BFS遍历，这里用的list\n",
    "            # 这里用set，否则会超时\n",
    "            # 这里用set也没问题，因为同一个点的路径信息已经在上一轮循环的prev_words里面记录了\n",
    "            tmp = set() \n",
    "            for word in queue:\n",
    "                for i in range(n):\n",
    "                    key = word[:i] + '_' + word[i + 1:]\n",
    "                    for neighbour in mp[key]:\n",
    "                        if neighbour == endWord:\n",
    "                            find = True\n",
    "\n",
    "                        # visited是全局的，因为是找最短路径，前几层如果出现过，当前层可以不用了，\n",
    "                        # 否则当前层满足，那之前的层肯定路径更短\n",
    "                        if not visited[neighbour]:\n",
    "                            tmp.add(neighbour)\n",
    "                            prev_words[neighbour].add(word)\n",
    "\n",
    "            for node in tmp:\n",
    "                # 当前层遍历完成之后再标记，因为可能有多条路径经过同一个word\n",
    "                visited[node] = True\n",
    "\n",
    "            queue = tmp\n",
    "\n",
    "            if find:\n",
    "                break\n",
    "\n",
    "        # 再根据target_level查找所有\n",
    "        if not find:\n",
    "            return []\n",
    "\n",
    "        res = []\n",
    "\n",
    "        def dfs(word, path):\n",
    "            if word == beginWord:\n",
    "                res.append(path.copy())\n",
    "                return\n",
    "\n",
    "            for prev in prev_words[word]:\n",
    "                dfs(prev,  [prev] + path)\n",
    "\n",
    "        dfs(endWord, [endWord])\n",
    "        return res\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "        neighbors = collections.defaultdict(list)\n",
    "        if beginWord in wordList:\n",
    "            wordList.remove(beginWord)\n",
    "        for x in [beginWord] + wordList:\n",
    "            tmp = list(x)\n",
    "            for i, c in enumerate(x):\n",
    "                tmp[i] = '*'\n",
    "                neighbors[x].append(''.join(tmp))\n",
    "                neighbors[''.join(tmp)].append(x)\n",
    "                tmp[i] = c\n",
    "        from1 = {beginWord: []}\n",
    "        ls1 = [beginWord]\n",
    "        from2 = {endWord: []}\n",
    "        ls2 = [endWord]\n",
    "        visited1 = set()\n",
    "        visited2 = set()\n",
    "        res = set()\n",
    "        flag = True\n",
    "        while len(ls1) > 0 or len(ls2) > 0:\n",
    "            sz1 = len(ls1)\n",
    "            tmp_vis = set()\n",
    "            for _ in range(sz1):\n",
    "                tmp = ls1.pop(0)\n",
    "                for x in neighbors[tmp]:\n",
    "                    if x in visited2:\n",
    "                        res.add(x)\n",
    "                        flag = False\n",
    "                    if x not in visited1:\n",
    "                        if x not in tmp_vis:\n",
    "                            tmp_vis.add(x)\n",
    "                            ls1.append(x)\n",
    "                        if x not in from1:\n",
    "                            from1[x] = []\n",
    "                        from1[x].append(tmp)\n",
    "            visited1 = visited1 | tmp_vis\n",
    "            if not flag:\n",
    "                break\n",
    "            sz2 = len(ls2)\n",
    "            tmp_vis = set()\n",
    "            for _ in range(sz2):\n",
    "                tmp = ls2.pop(0)\n",
    "                for x in neighbors[tmp]:\n",
    "                    if x in visited1:\n",
    "                        res.add(x)\n",
    "                        flag = False\n",
    "                    if x not in visited2:\n",
    "                        if x not  in tmp_vis:\n",
    "                            tmp_vis.add(x)\n",
    "                            ls2.append(x)\n",
    "                        if x not in from2:\n",
    "                            from2[x] = []\n",
    "                        from2[x].append(tmp)\n",
    "            visited2 = visited2 | tmp_vis\n",
    "            if not flag:\n",
    "                break\n",
    "\n",
    "        def dfs(cur, target, from_, paths, ans):\n",
    "            for x in from_[cur]:\n",
    "                if x == target:\n",
    "                    ans.append(paths + [target])\n",
    "                    return\n",
    "                paths.append(x)\n",
    "                dfs(x, target, from_, paths, ans)\n",
    "                paths.pop()\n",
    "\n",
    "        ans = []\n",
    "        if len(res) > 0:\n",
    "            for x in res:\n",
    "                left = []\n",
    "                dfs(x, beginWord, from1, [x], left)\n",
    "                right = []\n",
    "                dfs(x, endWord, from2, [x], right)\n",
    "                for left_ in left:\n",
    "                    for right_ in right:\n",
    "                        tmp = left_[::-1]+right_[1:]\n",
    "                        ans.append(tmp[::2])\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        g = defaultdict(list)\n",
    "        def addEdge(word):\n",
    "            chars = list(word)\n",
    "            for i, ch in enumerate(chars):\n",
    "                chars[i] = '*'\n",
    "                newword = ''.join(chars)\n",
    "                g[word].append(newword)\n",
    "                g[newword].append(word)\n",
    "                chars[i] = ch\n",
    "        for word in wordList:\n",
    "            addEdge(word)\n",
    "\n",
    "        ans = []\n",
    "        if beginWord not in g:\n",
    "            addEdge(beginWord)\n",
    "        if endWord not in g:\n",
    "            return ans\n",
    "\n",
    "        q1 = deque([beginWord])\n",
    "        q2 = deque([endWord])\n",
    "        vis1 = defaultdict(list)\n",
    "        vis2 = defaultdict(list)\n",
    "        vis1[beginWord].append('')\n",
    "        vis2[endWord].append('')\n",
    "        def bfs(q1, vis1, vis2):\n",
    "            tmp = defaultdict(list)\n",
    "            meet = set()\n",
    "            for _ in range(len(q1)):\n",
    "                word = q1.popleft()\n",
    "                for nxtword in g[word]:\n",
    "                    if nxtword in vis1:\n",
    "                        continue\n",
    "                    if nxtword in vis2:\n",
    "                        meet.add(nxtword)\n",
    "                    if nxtword not in tmp:\n",
    "                        q1.append(nxtword)\n",
    "                    tmp[nxtword].append(word)\n",
    "            vis1.update(tmp)\n",
    "            return meet\n",
    "\n",
    "        while q1 and q2:\n",
    "            if len(q1) <= len(q2):\n",
    "                meet = bfs(q1, vis1, vis2)\n",
    "            else:\n",
    "                meet = bfs(q2, vis2, vis1)\n",
    "            if meet:\n",
    "                break\n",
    "\n",
    "        cur = []\n",
    "        def dfs(word, vis, path):\n",
    "            if not word:\n",
    "                path.append(cur.copy())\n",
    "                return \n",
    "            cur.append(word)\n",
    "            for preword in vis[word]:\n",
    "                dfs(preword, vis, path)\n",
    "            cur.pop()\n",
    "\n",
    "        for word in meet:\n",
    "            path1, path2 = [], []\n",
    "            dfs(word, vis1, path1)\n",
    "            dfs(word, vis2, path2)\n",
    "            for p1 in path1:\n",
    "                for p2 in path2:\n",
    "                    path = p1[:0:-1] + p2\n",
    "                    path = path[::2]\n",
    "                    if path[0] != beginWord:\n",
    "                        path = path[::-1]\n",
    "                    ans.append(path)\n",
    "        return ans\n",
    "            \n",
    "\n",
    "            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import defaultdict\n",
    "from typing import List\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        wordList = set(wordList + [beginWord])\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "\n",
    "        nexts = defaultdict(list)\n",
    "\n",
    "        # 获取每个单词的邻居\n",
    "        for word in wordList:\n",
    "            if nexts[word]:\n",
    "                continue\n",
    "            tWord = list(word)\n",
    "            for i in range(len(word)):\n",
    "                for letterInd in range(26):\n",
    "                    letter = chr(letterInd + 97)\n",
    "                    if letter == tWord[i]:\n",
    "                        continue\n",
    "                    tmp = tWord[i]\n",
    "                    tWord[i] = letter\n",
    "                    if ''.join(tWord) in wordList:\n",
    "                        nexts[word].append(''.join(tWord))\n",
    "                    tWord[i] = tmp\n",
    "\n",
    "        # BFS获取distance\n",
    "        dis = {}\n",
    "        queue = [(1, beginWord)]\n",
    "        vis = {beginWord}\n",
    "        while queue:\n",
    "            distance, word = queue.pop(0)\n",
    "            dis[word] = distance\n",
    "            if word == endWord:\n",
    "                break\n",
    "            for next in nexts[word]:\n",
    "                if next not in vis:\n",
    "                    vis.add(next)\n",
    "                    queue.append((distance + 1, next))\n",
    "\n",
    "        # DFS找到所有最短路径\n",
    "        res = []\n",
    "        def process(cur, r):\n",
    "            if cur == beginWord:\n",
    "                res.append(r.copy())\n",
    "                return\n",
    "\n",
    "            for next in nexts[cur]:\n",
    "                if next in dis and dis[next] == dis[cur] - 1:\n",
    "                    process(next, [next] + r)\n",
    "\n",
    "        process(endWord, [endWord])\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        wordlen = len(endWord)\n",
    "        edg = collections.defaultdict(set)\n",
    "        fake_edg = collections.defaultdict(list)\n",
    "        wordList.append(beginWord)\n",
    "        wordset = set(wordList)\n",
    "\n",
    "        if endWord not in wordset:\n",
    "            return []\n",
    "        \n",
    "        for word in wordset:\n",
    "            for i in range(1,wordlen+1):\n",
    "                tmp_word = word[:i-1] + '*' + word[i:]\n",
    "                fake_edg[tmp_word].append(word)\n",
    "\n",
    "        def add_edg(word):\n",
    "            sons = []\n",
    "            for j in range(1,wordlen+1):\n",
    "                tmp_word = word[:j-1] + '*' + word[j:]\n",
    "                sons += fake_edg[tmp_word]\n",
    "            sons = set(sons)\n",
    "            sons.remove(word)\n",
    "            edg[word] = sons\n",
    "        \n",
    "        preWords = defaultdict(list)\n",
    "        toSeen = deque([(beginWord, 1)])\n",
    "        beFound = {beginWord:1}\n",
    "\n",
    "        while toSeen:\n",
    "            curWord, level = toSeen.popleft()\n",
    "            add_edg(curWord)\n",
    "            for word in edg[curWord]:\n",
    "                if word not in beFound:\n",
    "                    beFound[word] = level + 1\n",
    "                    toSeen.append((word, level+1))\n",
    "                if beFound[word] == level + 1:\n",
    "                    preWords[word].append(curWord)\n",
    "            if endWord in beFound and level + 1 > beFound[endWord]:\n",
    "                break\n",
    "        \n",
    "        if endWord not in beFound:\n",
    "            return []\n",
    "\n",
    "        res = [[endWord]]\n",
    "        while res[0][0] != beginWord:\n",
    "            res = [[word] + r for r in res for word in preWords[r[0]]]\n",
    "        return res\n",
    "        \n",
    "\n",
    "\n",
    "\n",
    "                \n",
    "\n",
    "\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "        g = collections.defaultdict(set)\n",
    "        wordList.append(beginWord)\n",
    "        s = set(wordList)\n",
    "        cost = collections.defaultdict(lambda: math.inf)\n",
    "        for word in wordList:\n",
    "            for i, ch in enumerate(word):\n",
    "                for letter in 'abcdefghijklmnopqrstuvwxyz':\n",
    "                    if letter != ch:\n",
    "                        tmp = word[:i] + letter + word[i + 1:]\n",
    "                        if tmp in s:\n",
    "                            g[word].add(tmp)\n",
    "        q = collections.deque([beginWord])\n",
    "        cost[beginWord] = 0\n",
    "        res = []\n",
    "        while q:\n",
    "            cur_word = q.popleft()\n",
    "            for nxt in g[cur_word]:\n",
    "                if cost[nxt] == math.inf:\n",
    "                    cost[nxt] = cost[cur_word] + 1\n",
    "                    q.append(nxt)\n",
    "            if cost[endWord] != math.inf:\n",
    "                break\n",
    "        if cost[endWord] == math.inf:\n",
    "            return []\n",
    "        m = collections.defaultdict(set)\n",
    "        for word in wordList:\n",
    "            m[cost[word]].add(word)\n",
    "        g2 = collections.defaultdict(set)\n",
    "        for word in wordList:\n",
    "            g2[word] = g[word] & m[cost[word] - 1]\n",
    "        path = [endWord]\n",
    "\n",
    "        def dfs(word):\n",
    "            if word == beginWord:\n",
    "                res.append(path[:][::-1])\n",
    "                return\n",
    "            for nxt in g2[word]:\n",
    "                path.append(nxt)\n",
    "                dfs(nxt)\n",
    "                path.pop()\n",
    "\n",
    "        dfs(endWord)\n",
    "        return res\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self,beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        if endWord not in wordList or not endWord or not beginWord or not wordList:\n",
    "            return []\n",
    "\n",
    "        dictory = defaultdict(list)\n",
    "        L = len(beginWord)\n",
    "\n",
    "        # 准备过程  将字典中其中一位用*代替，建立map    \n",
    "        for word in wordList:\n",
    "            for i in range(L):\n",
    "                dictory[word[:i] + '*' + word[i+1:]].append(word)\n",
    "                \n",
    "        ans = []\n",
    "\n",
    "        queue_begin = [(beginWord, 1, [[beginWord]])]\n",
    "        visited_begin = {beginWord:[[beginWord]]}\n",
    "\n",
    "        minLevel = len(wordList) + 1 # 最大长度为字典长度+1\n",
    "\n",
    "        while queue_begin:\n",
    "            current_word,level, paths = queue_begin.pop(0)\n",
    "\n",
    "            if level > minLevel: continue            \n",
    "\n",
    "            for i in range(L):\n",
    "                tmp = current_word[:i] + '*' + current_word[i+1:]\n",
    "                for word in dictory[tmp]:\n",
    "                    if word == endWord:\n",
    "                        # 拼接路径\n",
    "                        for p in paths:\n",
    "                            minLevel = level\n",
    "                            ans.append(p + [endWord])\n",
    "                            \n",
    "                    elif word not in visited_begin:\n",
    "                        new_paths = [p+[word] for p in paths]\n",
    "                        visited_begin[current_word] = new_paths\n",
    "                        queue_begin.append((word, level+1, new_paths))\n",
    "\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        wordlen = len(endWord)\n",
    "        edg = collections.defaultdict(set)\n",
    "        fake_edg = collections.defaultdict(list)\n",
    "        wordList.append(beginWord)\n",
    "        wordset = set(wordList)\n",
    "\n",
    "        if endWord not in wordset:\n",
    "            return []\n",
    "        \n",
    "        for word in wordset:\n",
    "            for i in range(1,wordlen+1):\n",
    "                tmp_word = word[:i-1] + '*' + word[i:]\n",
    "                fake_edg[tmp_word].append(word)\n",
    "\n",
    "        def add_edg(word):\n",
    "            sons = []\n",
    "            for j in range(1,wordlen+1):\n",
    "                tmp_word = word[:j-1] + '*' + word[j:]\n",
    "                sons += fake_edg[tmp_word]\n",
    "            sons = set(sons)\n",
    "            sons.remove(word)\n",
    "            edg[word] = sons\n",
    "        \n",
    "        preWords = defaultdict(list)\n",
    "        toSeen = deque([(beginWord, 1)])\n",
    "        beFound = {beginWord:1}\n",
    "\n",
    "        while toSeen:\n",
    "            curWord, level = toSeen.popleft()\n",
    "            if curWord not in edg:\n",
    "                add_edg(curWord)\n",
    "            for word in edg[curWord]:\n",
    "                if word not in beFound:\n",
    "                    beFound[word] = level + 1\n",
    "                    toSeen.append((word, level+1))\n",
    "                if beFound[word] == level + 1:\n",
    "                    preWords[word].append(curWord)\n",
    "            if endWord in beFound and level + 1 > beFound[endWord]:\n",
    "                break\n",
    "        \n",
    "        if endWord not in beFound:\n",
    "            return []\n",
    "\n",
    "        res = [[endWord]]\n",
    "        while res[0][0] != beginWord:\n",
    "            res = [[word] + r for r in res for word in preWords[r[0]]]\n",
    "        return res\n",
    "        \n",
    "\n",
    "\n",
    "\n",
    "                \n",
    "\n",
    "\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from functools import lru_cache\n",
    "class Solution(object):\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        def get_next_words(word, word_set):\n",
    "            words = set()\n",
    "            for i in range(len(word)):\n",
    "                for c in 'abcdefghijklmnopqrstuvwxyz':\n",
    "                    next_word = word[:i] + c + word[i + 1:]\n",
    "                    if next_word != word and next_word in word_set:\n",
    "                        words.add(next_word)\n",
    "            return words\n",
    "\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "\n",
    "        word_set = set(wordList)  # 查询提高速度\n",
    "        adjoin_list = defaultdict(set)  # 邻接矩阵,存前向节点，不是后向节点的原因是判重很方便\n",
    "        word_level = defaultdict(set)   # 记录每一层遍历遇到的单词\n",
    "        word_level[0].add(beginWord)\n",
    "        depth = 0\n",
    "        find_flag = False # 是否找到\n",
    "\n",
    "        queue = {beginWord}\n",
    "        while queue:\n",
    "            new_queue = set()\n",
    "            depth += 1\n",
    "            for cur in queue:\n",
    "                for next_word in get_next_words(cur, word_set):\n",
    "                    if next_word == endWord: # 如果遇到终点，则标记True，这一层走完就跳出循环\n",
    "                        find_flag = True\n",
    "                    if next_word not in adjoin_list:\n",
    "                        new_queue.add(next_word)\n",
    "                        word_level[depth].add(next_word)\n",
    "                    adjoin_list[next_word].add(cur)\n",
    "\n",
    "            if find_flag:  # 这一层找到了一定是最短的\n",
    "                break\n",
    "            queue = new_queue\n",
    "\n",
    "        if not find_flag:  # 没找到\n",
    "            return []\n",
    "\n",
    "        # dfs回溯路径\n",
    "        @lru_cache(None)\n",
    "        def dfs(depth, tmp, next_word):\n",
    "            if depth == -1:\n",
    "                return (tmp, )\n",
    "            res = []\n",
    "            for cur_word in word_level[depth]:\n",
    "                if cur_word in adjoin_list[next_word]:\n",
    "                    res.extend(dfs(depth - 1, (cur_word, ) + tmp, cur_word))\n",
    "            return tuple(res)\n",
    "\n",
    "        return dfs(len(word_level) - 2, (endWord,), endWord)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        wordlen = len(endWord)\n",
    "        edg = collections.defaultdict(set)\n",
    "        fake_edg = collections.defaultdict(list)\n",
    "        wordList.append(beginWord)\n",
    "        wordset = set(wordList)\n",
    "\n",
    "        if endWord not in wordset:\n",
    "            return []\n",
    "        \n",
    "        for word in wordset:\n",
    "            for i in range(1,wordlen+1):\n",
    "                tmp_word = word[:i-1] + '*' + word[i:]\n",
    "                fake_edg[tmp_word].append(word)\n",
    "\n",
    "        def add_edg(word):\n",
    "            sons = []\n",
    "            for j in range(1,wordlen+1):\n",
    "                tmp_word = word[:j-1] + '*' + word[j:]\n",
    "                sons += fake_edg[tmp_word]\n",
    "            sons = set(sons)\n",
    "            sons.remove(word)\n",
    "            edg[word] = sons\n",
    "        \n",
    "        preWords = defaultdict(list)\n",
    "        toSeen = deque([(beginWord, 1)])\n",
    "        beFound = {beginWord:1}\n",
    "\n",
    "        while toSeen:\n",
    "            curWord, level = toSeen.popleft()\n",
    "            if curWord not in edg:\n",
    "                add_edg(curWord)\n",
    "            for word in edg[curWord]:\n",
    "                if word not in beFound:\n",
    "                    beFound[word] = level + 1\n",
    "                    toSeen.append((word, level+1))\n",
    "                if beFound[word] == level + 1:\n",
    "                    preWords[word].append(curWord)\n",
    "            if endWord in beFound and level + 1 > beFound[endWord]:\n",
    "                break\n",
    "        \n",
    "        if endWord not in beFound:\n",
    "            return []\n",
    "\n",
    "        res = [[endWord]]\n",
    "        while res[0][0] != beginWord:\n",
    "            res = [[word] + r for r in res for word in preWords[r[0]]]\n",
    "        return res\n",
    "        \n",
    "\n",
    "\n",
    "\n",
    "                \n",
    "\n",
    "\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Link:\n",
    "    def __init__(self,v) -> None:\n",
    "        self.next = None\n",
    "        self.v = v\n",
    "        self.deep = 1000000\n",
    "def cnt_if(s1,s2):\n",
    "    cnt = 0\n",
    "    for i in range(len(s1)):\n",
    "        if s1[i] != s2[i]:\n",
    "            cnt+=1\n",
    "    return cnt\n",
    "def dfs(g,answer,tmp,deep,endWord,n):\n",
    "    # print(tmp)\n",
    "    if n.v == endWord:\n",
    "        answer.append(tmp.copy())\n",
    "    if deep == 0:\n",
    "        return\n",
    "    where = n.next\n",
    "    while where is not None:\n",
    "        if n.deep > g[where.v].deep:\n",
    "            tmp.append(g[where.v].v)\n",
    "            dfs(g,answer,tmp,deep-1,endWord,g[where.v])\n",
    "            tmp.pop()\n",
    "        where = where.next\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "        g = []\n",
    "        bfs = []\n",
    "        for i in [beginWord]+wordList:\n",
    "            tmp = Link(i)\n",
    "            where = tmp\n",
    "            for j in range(len(wordList)):\n",
    "                if cnt_if(i,wordList[j]) == 1:# and cnt_if(i,endWord) >= cnt_if(wordList[j],endWord):\n",
    "                    where.next = Link(j+1)\n",
    "                    where = where.next\n",
    "            if cnt_if(i,beginWord) == 1:\n",
    "                where.next = Link(0)\n",
    "            g.append(tmp)\n",
    "            if i == endWord:\n",
    "                tmp.deep = 0\n",
    "                bfs.append(tmp)\n",
    "            \n",
    "        use = []\n",
    "        for i in [1]+wordList:\n",
    "            use.append(False)\n",
    "        deep = 0\n",
    "        while deep < len(wordList):\n",
    "            deep+=1\n",
    "            next = []\n",
    "            end = False\n",
    "            for i in bfs:\n",
    "                while i.next is not None:\n",
    "                    if use[i.next.v]:\n",
    "                        i = i.next\n",
    "                        continue\n",
    "                    use[i.next.v]=True\n",
    "                    g[i.next.v].deep=min(deep,g[i.next.v].deep)\n",
    "                    next.append(g[i.next.v])\n",
    "                    if g[i.next.v].v == beginWord:\n",
    "                        end=True\n",
    "                        break\n",
    "                    i = i.next\n",
    "            if end:\n",
    "                break\n",
    "            bfs = next\n",
    "        if not end:\n",
    "            return []\n",
    "        answer = []  \n",
    "        dfs(g,answer,[beginWord],deep,endWord,g[0])\n",
    "        return answer          \n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "\"\"\"\n",
    "\"hit\"\n",
    "\"hit\"\n",
    "[\"hit\"]\n",
    "\n",
    "\"hit\"\n",
    "\"cog\"\n",
    "[\"hot\",\"dot\",\"dog\",\"lot\",\"log\",\"cog\"]\n",
    "\n",
    "\"hit\"\n",
    "\"cog\"\n",
    "[\"hot\",\"dot\",\"dog\",\"lot\",\"log\"]\n",
    "\n",
    "\"hot\"\n",
    "\"dog\"\n",
    "[\"hot\",\"dog\"]\n",
    "\n",
    "\"qa\"\n",
    "\"sq\"\n",
    "[\"si\",\"go\",\"se\",\"cm\",\"so\",\"ph\",\"mt\",\"db\",\"mb\",\"sb\",\"kr\",\"ln\",\"tm\",\"le\",\"av\",\"sm\",\"ar\",\"ci\",\"ca\",\"br\",\"ti\",\"ba\",\"to\",\"ra\",\"fa\",\"yo\",\"ow\",\"sn\",\"ya\",\"cr\",\"po\",\"fe\",\"ho\",\"ma\",\"re\",\"or\",\"rn\",\"au\",\"ur\",\"rh\",\"sr\",\"tc\",\"lt\",\"lo\",\"as\",\"fr\",\"nb\",\"yb\",\"if\",\"pb\",\"ge\",\"th\",\"pm\",\"rb\",\"sh\",\"co\",\"ga\",\"li\",\"ha\",\"hz\",\"no\",\"bi\",\"di\",\"hi\",\"qa\",\"pi\",\"os\",\"uh\",\"wm\",\"an\",\"me\",\"mo\",\"na\",\"la\",\"st\",\"er\",\"sc\",\"ne\",\"mn\",\"mi\",\"am\",\"ex\",\"pt\",\"io\",\"be\",\"fm\",\"ta\",\"tb\",\"ni\",\"mr\",\"pa\",\"he\",\"lr\",\"sq\",\"ye\"]\n",
    "\"\"\"\n",
    "\n",
    "class Solution:\n",
    "    \"\"\" DFS\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        wordSet = set(wordList)\n",
    "        if endWord not in wordSet: return []\n",
    "        if beginWord == endWord: return [beginWord]\n",
    "\n",
    "        wordSet.discard(beginWord)\n",
    "        path = [beginWord]\n",
    "        solved = [False]\n",
    "        self.dfs(wordSet, beginWord, endWord, path, solved)\n",
    "        if solved[0]: return path\n",
    "        return []\n",
    "    def dfs(self, wordSet, word, endWord, path, solved):\n",
    "        if word == endWord:\n",
    "            solved[0] = True\n",
    "            return\n",
    "        for nextWord in self.getNext(word, wordSet):\n",
    "            wordSet.discard(nextWord)\n",
    "            path.append(nextWord)\n",
    "            self.dfs(wordSet, nextWord, endWord, path, solved)\n",
    "            if not solved[0]:\n",
    "                path.pop()\n",
    "            else:\n",
    "                break\n",
    "    def getNext(self, word, wordSet):\n",
    "        charList = list(word)\n",
    "        res = []\n",
    "        for i in range(len(charList)):\n",
    "            ogChar = charList[i]\n",
    "            for _a in range(26):\n",
    "                a = chr(ord('a')+_a)\n",
    "                if charList[i] == a: continue\n",
    "                charList[i] = a\n",
    "                _word = ''.join(charList)\n",
    "                if _word in wordSet:\n",
    "                    res.append(_word)\n",
    "            charList[i] = ogChar\n",
    "        return res\n",
    "    \"\"\"\n",
    "    \"\"\"\n",
    "    # BFS\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        wordSet = set(wordList)\n",
    "        if endWord not in wordSet: return []\n",
    "        if beginWord == endWord: return [beginWord]\n",
    "        que = deque([beginWord])\n",
    "        wordSet.discard(beginWord)\n",
    "        link = {beginWord: None}\n",
    "        while que:\n",
    "            word = que.popleft()\n",
    "            for nextWord in self.getNext(word, wordSet):\n",
    "                wordSet.discard(nextWord)\n",
    "                link[nextWord] = word\n",
    "                que.append(nextWord)\n",
    "                if nextWord == endWord:\n",
    "                    res = []\n",
    "                    curr = nextWord\n",
    "                    while link[curr] is not None:\n",
    "                        res.append(curr)\n",
    "                        curr = link[curr]\n",
    "                    res.append(beginWord)\n",
    "                    return res[::-1]\n",
    "        return []\n",
    "    def getNext(self, word, wordSet):\n",
    "        charList = list(word)\n",
    "        res = []\n",
    "        for i in range(len(charList)):\n",
    "            ogChar = charList[i]\n",
    "            for _a in range(26):\n",
    "                a = chr(ord('a')+_a)\n",
    "                if charList[i] == a: continue\n",
    "                charList[i] = a\n",
    "                _word = ''.join(charList)\n",
    "                if _word in wordSet:\n",
    "                    res.append(_word)\n",
    "            charList[i] = ogChar\n",
    "        return res\n",
    "    \"\"\"\n",
    "    # Bidirectional BFS\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        wordSet = set(wordList)\n",
    "        if endWord not in wordSet: return []\n",
    "        if beginWord == endWord: return [beginWord]\n",
    "        queBegin = deque([beginWord])\n",
    "        linkBegin = {beginWord: None}\n",
    "        queEnd = deque([endWord])\n",
    "        linkEnd = {endWord: None}\n",
    "\n",
    "        while queBegin and queEnd:\n",
    "            beginLen = len(queBegin)\n",
    "            while beginLen:\n",
    "                beg = queBegin.popleft()\n",
    "                for nextWord in self.getNext(beg, wordSet, linkBegin):\n",
    "                    linkBegin[nextWord] = beg\n",
    "                    if nextWord in linkEnd:\n",
    "                        return self.build(linkBegin, linkEnd, nextWord)\n",
    "                    queBegin.append(nextWord)\n",
    "                beginLen -= 1\n",
    "\n",
    "            endLen = len(queEnd)\n",
    "            while endLen:\n",
    "                end = queEnd.popleft()\n",
    "                for nextWord in self.getNext(end, wordSet, linkEnd):\n",
    "                    linkEnd[nextWord] = end\n",
    "                    if nextWord in linkBegin:\n",
    "                        return self.build(linkBegin, linkEnd, nextWord)\n",
    "                    queEnd.append(nextWord)\n",
    "                endLen -= 1\n",
    "        return []\n",
    "    def build(self, linkBegin, linkEnd, intersect):\n",
    "        curr = intersect\n",
    "        res = [curr]\n",
    "        while linkBegin[curr] is not None:\n",
    "            res.append(linkBegin[curr])\n",
    "            curr = linkBegin[curr]\n",
    "        res = res[::-1]\n",
    "        while linkEnd[intersect] is not None:\n",
    "            res.append(linkEnd[intersect])\n",
    "            intersect = linkEnd[intersect]\n",
    "        return res\n",
    "    def getNext(self, word, wordSet, link):\n",
    "        charList = list(word)\n",
    "        res = []\n",
    "        for i in range(len(charList)):\n",
    "            ogChar = charList[i]\n",
    "            for _a in range(26):\n",
    "                a = chr(ord('a')+_a)\n",
    "                if charList[i] == a: continue\n",
    "                charList[i] = a\n",
    "                _word = ''.join(charList)\n",
    "                if _word in wordSet and _word not in link:\n",
    "                    res.append(_word)\n",
    "            charList[i] = ogChar\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        n = len(wordList)\n",
    "        q = deque()\n",
    "        mp = dict()\n",
    "        vis = dict()\n",
    "        res = []\n",
    "        q.append(beginWord)\n",
    "        if endWord not in set(wordList):\n",
    "            return []\n",
    "\n",
    "        for w in wordList:\n",
    "            vis.setdefault(w, False)\n",
    "\n",
    "\n",
    "\n",
    "        def check(a, b):\n",
    "            cnt = 0\n",
    "            for i in range(len(a)):\n",
    "                if a[i] != b[i]:\n",
    "                    cnt += 1\n",
    "            return cnt == 1\n",
    "\n",
    "        match = False\n",
    "        while q:\n",
    "            s = q.popleft()\n",
    "            if s == endWord:\n",
    "                match = True\n",
    "                break\n",
    "            for w in wordList:\n",
    "                if not vis[w] and check(s, w):\n",
    "                    q.append(w)\n",
    "                    vis[w] = True\n",
    "                    mp[w] = s\n",
    "\n",
    "        if not match:\n",
    "            return []\n",
    "        \n",
    "\n",
    "        s = endWord\n",
    "        while s != beginWord:\n",
    "            res.append(s)\n",
    "            s = mp[s]\n",
    "        res.append(beginWord)\n",
    "        return res[::-1]\n",
    "\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import deque\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        queue = deque()\n",
    "        queue.append(beginWord)\n",
    "        n = len(wordList)\n",
    "        # 记录当前结果是从哪个转变来的\n",
    "        vis = {beginWord: None}\n",
    "\n",
    "        def oneDif(s1: str, s2: str):\n",
    "            count = 0\n",
    "            if len(s1) != len(s2):\n",
    "                return False\n",
    "            for i in range(len(s1)):\n",
    "                if s1[i] != s2[i]:\n",
    "                    count += 1\n",
    "                    if count > 1:\n",
    "                        return False\n",
    "            return True\n",
    "\n",
    "        while queue:\n",
    "            s = queue.popleft()\n",
    "            for i in range(n):\n",
    "                if wordList[i] not in vis and oneDif(s, wordList[i]):\n",
    "                    queue.append(wordList[i])\n",
    "                    vis[wordList[i]] = s\n",
    "                    if wordList[i] == endWord:\n",
    "                        ans = [endWord]\n",
    "                        temp = endWord\n",
    "                        while temp != beginWord:\n",
    "                            ans.append(vis[temp])\n",
    "                            temp = vis[temp]\n",
    "                        ans.reverse()\n",
    "                        return ans\n",
    "        return []\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        n = len(wordList)\n",
    "        q = [beginWord]\n",
    "        mp = dict()\n",
    "        vis = dict()\n",
    "        res = []\n",
    "\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "\n",
    "        for w in wordList:\n",
    "            vis.setdefault(w, False)\n",
    "\n",
    "\n",
    "\n",
    "        def check(a, b):\n",
    "            cnt = 0\n",
    "            for i in range(len(a)):\n",
    "                if a[i] != b[i]:\n",
    "                    cnt += 1\n",
    "            return cnt == 1\n",
    "\n",
    "        match = False\n",
    "        while q:\n",
    "            s = q.pop(0)\n",
    "            if s == endWord:\n",
    "                match = True\n",
    "                break\n",
    "            for w in wordList:\n",
    "                if not vis[w] and check(s, w):\n",
    "                    q.append(w)\n",
    "                    vis[w] = True\n",
    "                    mp[w] = s\n",
    "\n",
    "        if not match:\n",
    "            return []\n",
    "        \n",
    "\n",
    "        s = endWord\n",
    "        while s != beginWord:\n",
    "            res.append(s)\n",
    "            s = mp[s]\n",
    "        res.append(beginWord)\n",
    "        return res[::-1]\n",
    "\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        s = set(wordList)\n",
    "        if endWord not in s:\n",
    "            return []\n",
    "        que = deque()\n",
    "        que.append([beginWord,[beginWord]])\n",
    "        vis = set()\n",
    "        vis.add(beginWord)\n",
    "        while len(que)>0:\n",
    "            node = que.popleft()\n",
    "            if node[0] == endWord:\n",
    "                return node[1]\n",
    "            for nex in wordList:\n",
    "                if nex not in vis:\n",
    "                    cur,cns = node[0],0\n",
    "                    for i in range(0,len(nex)):\n",
    "                        if nex[i] != cur[i]:\n",
    "                            cns+=1\n",
    "                        if cns == 2:\n",
    "                            break\n",
    "                    if cns == 1:\n",
    "                        li = node[1].copy()\n",
    "                        li.append(nex)\n",
    "                        que.append([nex,li])\n",
    "                        vis.add(nex)\n",
    "        return []    \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        s = set(wordList)\n",
    "        if endWord not in s:\n",
    "            return []\n",
    "        que = []\n",
    "        que.append([beginWord,[beginWord]])\n",
    "        vis = set()\n",
    "        vis.add(beginWord)\n",
    "        while len(que)>0:\n",
    "            node = que.pop(0)\n",
    "            if node[0] == endWord:\n",
    "                return node[1]\n",
    "            for nex in wordList:\n",
    "                if nex not in vis:\n",
    "                    cur = node[0]\n",
    "                    cns = 0\n",
    "                    for i in range(0,len(nex)):\n",
    "                        if nex[i] != cur[i]:\n",
    "                            cns+=1\n",
    "                        if cns == 2:\n",
    "                            break\n",
    "                    if cns == 1:\n",
    "                        li = node[1].copy()\n",
    "                        li.append(nex)\n",
    "                        que.append([nex,li])\n",
    "                        vis.add(nex)\n",
    "        return []    \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "\"\"\"\n",
    "\"hit\"\n",
    "\"hit\"\n",
    "[\"hit\"]\n",
    "\n",
    "\"hit\"\n",
    "\"cog\"\n",
    "[\"hot\",\"dot\",\"dog\",\"lot\",\"log\",\"cog\"]\n",
    "\n",
    "\"hit\"\n",
    "\"cog\"\n",
    "[\"hot\",\"dot\",\"dog\",\"lot\",\"log\"]\n",
    "\n",
    "\"hot\"\n",
    "\"dog\"\n",
    "[\"hot\",\"dog\"]\n",
    "\n",
    "\"qa\"\n",
    "\"sq\"\n",
    "[\"si\",\"go\",\"se\",\"cm\",\"so\",\"ph\",\"mt\",\"db\",\"mb\",\"sb\",\"kr\",\"ln\",\"tm\",\"le\",\"av\",\"sm\",\"ar\",\"ci\",\"ca\",\"br\",\"ti\",\"ba\",\"to\",\"ra\",\"fa\",\"yo\",\"ow\",\"sn\",\"ya\",\"cr\",\"po\",\"fe\",\"ho\",\"ma\",\"re\",\"or\",\"rn\",\"au\",\"ur\",\"rh\",\"sr\",\"tc\",\"lt\",\"lo\",\"as\",\"fr\",\"nb\",\"yb\",\"if\",\"pb\",\"ge\",\"th\",\"pm\",\"rb\",\"sh\",\"co\",\"ga\",\"li\",\"ha\",\"hz\",\"no\",\"bi\",\"di\",\"hi\",\"qa\",\"pi\",\"os\",\"uh\",\"wm\",\"an\",\"me\",\"mo\",\"na\",\"la\",\"st\",\"er\",\"sc\",\"ne\",\"mn\",\"mi\",\"am\",\"ex\",\"pt\",\"io\",\"be\",\"fm\",\"ta\",\"tb\",\"ni\",\"mr\",\"pa\",\"he\",\"lr\",\"sq\",\"ye\"]\n",
    "\"\"\"\n",
    "\n",
    "class Solution:\n",
    "    \"\"\" DFS\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        wordSet = set(wordList)\n",
    "        if endWord not in wordSet: return []\n",
    "        if beginWord == endWord: return [beginWord]\n",
    "\n",
    "        wordSet.discard(beginWord)\n",
    "        path = [beginWord]\n",
    "        solved = [False]\n",
    "        self.dfs(wordSet, beginWord, endWord, path, solved)\n",
    "        if solved[0]: return path\n",
    "        return []\n",
    "    def dfs(self, wordSet, word, endWord, path, solved):\n",
    "        if word == endWord:\n",
    "            solved[0] = True\n",
    "            return\n",
    "        for nextWord in self.getNext(word, wordSet):\n",
    "            wordSet.discard(nextWord)\n",
    "            path.append(nextWord)\n",
    "            self.dfs(wordSet, nextWord, endWord, path, solved)\n",
    "            if not solved[0]:\n",
    "                path.pop()\n",
    "            else:\n",
    "                break\n",
    "    def getNext(self, word, wordSet):\n",
    "        charList = list(word)\n",
    "        res = []\n",
    "        for i in range(len(charList)):\n",
    "            ogChar = charList[i]\n",
    "            for _a in range(26):\n",
    "                a = chr(ord('a')+_a)\n",
    "                if charList[i] == a: continue\n",
    "                charList[i] = a\n",
    "                _word = ''.join(charList)\n",
    "                if _word in wordSet:\n",
    "                    res.append(_word)\n",
    "            charList[i] = ogChar\n",
    "        return res\n",
    "    \"\"\"\n",
    "\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        wordSet = set(wordList)\n",
    "        if endWord not in wordSet: return []\n",
    "        if beginWord == endWord: return [beginWord]\n",
    "        que = deque([beginWord])\n",
    "        wordSet.discard(beginWord)\n",
    "        link = {beginWord: None}\n",
    "        while que:\n",
    "            word = que.popleft()\n",
    "            for nextWord in self.getNext(word, wordSet):\n",
    "                wordSet.discard(nextWord)\n",
    "                link[nextWord] = word\n",
    "                que.append(nextWord)\n",
    "                if nextWord == endWord:\n",
    "                    res = []\n",
    "                    curr = nextWord\n",
    "                    while link[curr] is not None:\n",
    "                        res.append(curr)\n",
    "                        curr = link[curr]\n",
    "                    res.append(beginWord)\n",
    "                    return res[::-1]\n",
    "        return []\n",
    "    def getNext(self, word, wordSet):\n",
    "        charList = list(word)\n",
    "        res = []\n",
    "        for i in range(len(charList)):\n",
    "            ogChar = charList[i]\n",
    "            for _a in range(26):\n",
    "                a = chr(ord('a')+_a)\n",
    "                if charList[i] == a: continue\n",
    "                charList[i] = a\n",
    "                _word = ''.join(charList)\n",
    "                if _word in wordSet:\n",
    "                    res.append(_word)\n",
    "            charList[i] = ogChar\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\r\n",
    "    def match(self, s1, s2) -> bool:\r\n",
    "        change = False\r\n",
    "        for c1, c2 in zip(s1, s2):\r\n",
    "            if c1 != c2:\r\n",
    "                if change:\r\n",
    "                    return False\r\n",
    "                else:\r\n",
    "                    change = True\r\n",
    "        return change\r\n",
    "\r\n",
    "    def dfs(self, key, target, wordList, visited, path) -> int:\r\n",
    "        if visited[key]:\r\n",
    "            return -1\r\n",
    "        visited[key] = True\r\n",
    "        v = wordList[key]\r\n",
    "        if self.match(v, target):\r\n",
    "            return key\r\n",
    "        for i, u in enumerate(wordList):\r\n",
    "            if visited[i]:\r\n",
    "                continue\r\n",
    "            if len(u) != len(v):\r\n",
    "                visited[i] = True\r\n",
    "            if self.match(u, v):\r\n",
    "                path[i] = key\r\n",
    "                j = self.dfs(i, target, wordList, visited, path)\r\n",
    "                if j != -1:\r\n",
    "                    return j\r\n",
    "        return -1\r\n",
    "\r\n",
    "    def findLadders(\r\n",
    "        self, beginWord: str, endWord: str, wordList: List[str]\r\n",
    "    ) -> List[str]:\r\n",
    "        if len(beginWord) != len(endWord) or endWord not in wordList:\r\n",
    "            return []\r\n",
    "        visited = [False] * len(wordList)\r\n",
    "        path = [-1] * len(wordList)\r\n",
    "\r\n",
    "        key = self.dfs(wordList.index(endWord), beginWord, wordList, visited, path)\r\n",
    "        if key == -1:\r\n",
    "            return []\r\n",
    "        trans = [beginWord]\r\n",
    "        while key != -1:\r\n",
    "            trans.append(wordList[key])\r\n",
    "            key = path[key]\r\n",
    "        return trans\r\n",
    "\r\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def match(self, s1, s2) -> bool:\n",
    "        change = False\n",
    "        for c1, c2 in zip(s1, s2):\n",
    "            if c1 != c2:\n",
    "                if change:\n",
    "                    return False\n",
    "                else:\n",
    "                    change = True\n",
    "        return change\n",
    "\n",
    "    def dfs(self, key, target, wordList, visited, path) -> int:\n",
    "        if visited[key]:\n",
    "            return -1\n",
    "        visited[key] = True\n",
    "        v = wordList[key]\n",
    "        if self.match(v, target):\n",
    "            return key\n",
    "        for i, u in enumerate(wordList):\n",
    "            if visited[i]:\n",
    "                continue\n",
    "            if len(u) != len(v):\n",
    "                visited[i] = True\n",
    "            if self.match(u, v):\n",
    "                path[i] = key\n",
    "                j = self.dfs(i, target, wordList, visited, path)\n",
    "                if j != -1:\n",
    "                    return j\n",
    "        return -1\n",
    "\n",
    "    def findLadders(\n",
    "        self, beginWord: str, endWord: str, wordList: List[str]\n",
    "    ) -> List[str]:\n",
    "        if len(beginWord) != len(endWord) or endWord not in wordList:\n",
    "            return []\n",
    "        visited = [False] * len(wordList)\n",
    "        path = [-1] * len(wordList)\n",
    "\n",
    "        key = self.dfs(wordList.index(endWord), beginWord, wordList, visited, path)\n",
    "        if key == -1:\n",
    "            return []\n",
    "        trans = [beginWord]\n",
    "        while key != -1:\n",
    "            trans.append(wordList[key])\n",
    "            key = path[key]\n",
    "        return trans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from typing import List\n",
    "from collections import deque\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        # 将wordList转换为一个集合，以便于进行O(1)查找\n",
    "        wordSet = set(wordList)\n",
    "        if endWord not in wordSet:\n",
    "            return []\n",
    "        \n",
    "        # 初始化BFS队列和路径记录字典\n",
    "        queue = deque([beginWord])\n",
    "        path_dict = {beginWord: [beginWord]}\n",
    "        \n",
    "        while queue:\n",
    "            # 在每一层中，存储到达该层节点的所有可能路径\n",
    "            level_dict = {}\n",
    "            for _ in range(len(queue)):\n",
    "                # 弹出当前层的一个节点\n",
    "                current_word = queue.popleft()\n",
    "                \n",
    "                # 构造所有可能的下一个单词\n",
    "                for i in range(len(current_word)):\n",
    "                    for c in \"abcdefghijklmnopqrstuvwxyz\":\n",
    "                        next_word = current_word[:i] + c + current_word[i+1:]\n",
    "                        \n",
    "                        if next_word in wordSet:\n",
    "                            # 如果找到了目标单词，直接返回路径\n",
    "                            if next_word == endWord:\n",
    "                                return path_dict[current_word] + [endWord]\n",
    "                            \n",
    "                            # 只有当这个词没有出现在更短的路径中时，才添加进队列和字典\n",
    "                            if next_word not in path_dict:\n",
    "                                queue.append(next_word)\n",
    "                                level_dict[next_word] = path_dict[current_word] + [next_word]\n",
    "            \n",
    "            # 更新路径字典\n",
    "            path_dict.update(level_dict)\n",
    "            \n",
    "            # 从wordSet中删除已经访问过的单词\n",
    "            wordSet -= set(level_dict.keys())\n",
    "        \n",
    "        return []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        wordList = set(wordList)\n",
    "        path = [beginWord]  # the first path starts with beginWord\n",
    "        paths = collections.deque([path])\n",
    "        visited = set()\n",
    "        res = []\n",
    "        step = 1 # the first step is beginWord\n",
    "        minStep = 0x7fffffff\n",
    "        word_len = len(beginWord)  # all words has the same length\n",
    "        while paths:\n",
    "            curr_path = paths.popleft() # pop a path\n",
    "            if len(curr_path) > step: #  the number of word in current path\n",
    "                for w in visited: # words processed in previous can be removed from the set\n",
    "                    wordList.remove(w)\n",
    "                visited.clear() # new set\n",
    "                step = len(curr_path) \n",
    "                if step > minStep:  # larger then current minimum, do not need to continue\n",
    "                    break\n",
    "            # continue process the path with the length of step\n",
    "            last = curr_path[-1] # last word in current path\n",
    "            for i in range(word_len):\n",
    "                for c in 'abcdefghijklmnopqrstuvwxyz':\n",
    "                    nword = last[:i] + c + last[i+1:]\n",
    "                    if nword in wordList: # nword is reachable\n",
    "                        visited.add(nword) \n",
    "                        npath = curr_path[:] + [nword]  # copy the parent path, append the new word, generate a new path\n",
    "                        if nword == endWord:\n",
    "                            return npath\n",
    "                        else:\n",
    "                            paths.append(npath)         \n",
    "        return \"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "\n",
    "    def check_translate(self, a: str, b: str) -> bool:  #是否恰好有1位不同\n",
    "        if len(a) != len(b):\n",
    "            return False\n",
    "        n = len(a)\n",
    "        cnt = 0\n",
    "        for i in range(n):\n",
    "            if a[i] != b[i]:\n",
    "                cnt += 1\n",
    "        return cnt == 1\n",
    "\n",
    "    def dfs(self, curWord: str, endWord: str, wordList: List[str]) -> bool:\n",
    "        if curWord == endWord:                      #剪枝\n",
    "            return True\n",
    "        n = len(wordList)\n",
    "        for i in range(n):\n",
    "            if self.visited[i] == True or self.check_translate(curWord, wordList[i]) == False:\n",
    "                continue\n",
    "            self.visited[i] = True\n",
    "            self.path.append(wordList[i])\n",
    "            if self.dfs(wordList[i], endWord, wordList) == True:\n",
    "                return True\n",
    "            self.path.pop(-1)                       #半回溯\n",
    "            #self.visited[i] = False      #不是单纯的回溯   因为之间是有循环的 不是一棵树  是一个有环图！！！！！！！！！！！！！！\n",
    "        return False\n",
    "\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        n = len(wordList)\n",
    "        self.visited = [False for _ in range(n)]\n",
    "        self.path = [beginWord]\n",
    "        if self.dfs(beginWord, endWord, wordList) == True:\n",
    "            return self.path[:]\n",
    "        else:\n",
    "            return []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "\n",
    "    def check_translate(self, a: str, b: str) -> bool:  #是否恰好有1位不同\n",
    "        if len(a) != len(b):\n",
    "            return False\n",
    "        n = len(a)\n",
    "        cnt = 0\n",
    "        for i in range(n):\n",
    "            if a[i] != b[i]:\n",
    "                cnt += 1\n",
    "        return cnt == 1\n",
    "\n",
    "    def dfs(self, curWord: str, endWord: str, wordList: List[str]) -> bool:\n",
    "        if curWord == endWord:                      #剪枝\n",
    "            return True\n",
    "        n = len(wordList)\n",
    "        for i in range(n):\n",
    "            if self.visited[i] == True or self.check_translate(curWord, wordList[i]) == False:\n",
    "                continue\n",
    "            self.visited[i] = True\n",
    "            self.path.append(wordList[i])\n",
    "            if self.dfs(wordList[i], endWord, wordList) == True:\n",
    "                return True\n",
    "            self.path.pop(-1)                       #半回溯\n",
    "            #self.visited[i] = False      #不是单纯的回溯   因为之间是有循环的 不是一棵树  是一个有环图！！！！！！！！！！！！！！\n",
    "        return False\n",
    "\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        n = len(wordList)\n",
    "        self.visited = [False for _ in range(n)]\n",
    "        self.path = [beginWord]\n",
    "        if self.dfs(beginWord, endWord, wordList) == True:\n",
    "            return self.path[:]\n",
    "        else:\n",
    "            return []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from typing import List\n",
    "\n",
    "class Solution:\n",
    "    def canTranslate(self, from_word: str, to_word: str) -> bool:\n",
    "        if len(from_word) != len(to_word):\n",
    "            return False\n",
    "        count = 0\n",
    "        for i in range(len(from_word)):\n",
    "            if from_word[i] != to_word[i]:\n",
    "                count += 1\n",
    "        return count == 1\n",
    "\n",
    "    def hasRoute(self, curWord: str, endWord: str, wordList: List[str], \n",
    "                    visited: List[bool], result: List[str]) -> bool:\n",
    "        if curWord == endWord:\n",
    "            return True\n",
    "        for i in range(len(wordList)):\n",
    "            if visited[i] or not self.canTranslate(curWord, wordList[i]):\n",
    "                continue\n",
    "            visited[i] = True\n",
    "            result.append(wordList[i])\n",
    "            if self.hasRoute(wordList[i], endWord, wordList, visited, result):\n",
    "                return True\n",
    "            result.pop()\n",
    "            # 如果运行到这一步，意味着无法从i这个点找到路径，所以visited[i]无需改为False.\n",
    "            # visited[i] = False\n",
    "        return False\n",
    "\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        result = [beginWord]\n",
    "        visited = [False] * len(wordList)\n",
    "        if self.hasRoute(beginWord, endWord, wordList, visited, result):\n",
    "            return result\n",
    "        return []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "        def check(fromWord,toWord):\n",
    "            if len(fromWord) != len(toWord):\n",
    "                return False\n",
    "            diff = 0\n",
    "            for i in range(len(fromWord)):\n",
    "                if fromWord[i] != toWord[i]:\n",
    "                    diff += 1\n",
    "            return diff == 1\n",
    "\n",
    "        def dfs(curWord):\n",
    "            if curWord == endWord:\n",
    "                return True\n",
    "            for i in range(len(wordList)):\n",
    "                if visited[i] or not check(wordList[i],curWord):\n",
    "                    continue\n",
    "                visited[i] = True\n",
    "                res.append(wordList[i])\n",
    "                if dfs(wordList[i]):\n",
    "                    return True\n",
    "                res.pop()\n",
    "                # 如果运行到这一步，意味着无法从i这个点找到路径，所以visited[i]无需改为false\n",
    "            return False\n",
    "        print(beginWord,wordList[0])\n",
    "        print(check(\"hit\",\"hot\"))\n",
    "        res = list()\n",
    "        res.append(beginWord)\n",
    "        visited = [False for _ in range(len(wordList))]\n",
    "        if dfs(beginWord):\n",
    "            return res\n",
    "        return []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        def dfs(cur,end,l,path):\n",
    "            if cur==end:\n",
    "                return True\n",
    "            for i in range(len(l)):\n",
    "                if l[i] not in seen and translate(cur,l[i]):\n",
    "                    seen.add(l[i])\n",
    "                    path.append(l[i])\n",
    "                    if dfs(l[i],end,l,path):\n",
    "                        return True\n",
    "                    path.pop()\n",
    "            return False\n",
    "        def translate(from_,to_):\n",
    "            count=0\n",
    "            if len(from_)!=len(to_):\n",
    "                return False\n",
    "            for i in range(len(from_)):\n",
    "                if from_[i]!=to_[i]:\n",
    "                    count+=1\n",
    "            return count==1\n",
    "        seen=set()\n",
    "        path=[beginWord]\n",
    "        if dfs(beginWord,endWord,wordList,path):\n",
    "            return path\n",
    "        return []\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        ret = [beginWord]\n",
    "        visited = [False for i in range(len(wordList))]\n",
    "        def dfs(now):\n",
    "            if now == endWord:\n",
    "                return True\n",
    "            for i, w in enumerate(wordList):\n",
    "                if not visited[i] and [w[i] != now[i] for i in range(len(now))].count(True) == 1:\n",
    "                    visited[i] = True\n",
    "                    ret.append(w)\n",
    "                    if dfs(w):\n",
    "                        return True\n",
    "                    ret.pop()\n",
    "            return False\n",
    "        return ret if dfs(beginWord) else []\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        ans = [beginWord]\n",
    "        vis = set(ans)\n",
    "        def check(x, y):\n",
    "            cnt = 0\n",
    "            for a, b in zip(x, y):\n",
    "                if a != b:\n",
    "                    cnt += 1\n",
    "            return cnt == 1\n",
    "\n",
    "        def dfs(word):\n",
    "            for x in wordList:\n",
    "                if x not in vis and check(word, x):\n",
    "                    vis.add(x)\n",
    "                    ans.append(x)\n",
    "                    if x == endWord:\n",
    "                        return True\n",
    "                    if dfs(x):\n",
    "                        return True\n",
    "                    ans.pop()\n",
    "                    # vis.remove(x)\n",
    "        if dfs(beginWord):\n",
    "            return ans\n",
    "        return []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "      ans=[beginWord]\n",
    "      visit=[0 for _ in range(len(wordList))]\n",
    "      def dfs(cur):\n",
    "        if cur==endWord:\n",
    "          return True\n",
    "        for i in range(len(wordList)):\n",
    "          if not visit[i] and [wordList[i][j]!=cur[j] for j in range(len(cur))].count(1)==1:\n",
    "            visit[i]=1\n",
    "            ans.append(wordList[i])\n",
    "            if dfs(wordList[i]):\n",
    "              return True\n",
    "            ans.pop()\n",
    "        return False\n",
    "      return ans if dfs(beginWord) else []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "def is_word_similar(word1, word2):\n",
    "    diff_letter_count = 0\n",
    "    for i in range(len(word1)):\n",
    "        if word1[i] != word2[i]:\n",
    "            diff_letter_count += 1\n",
    "        if diff_letter_count >= 2:\n",
    "            return False\n",
    "\n",
    "    if diff_letter_count == 0:\n",
    "        return False\n",
    "    return True\n",
    "\n",
    "\n",
    "def transform(source_word, target_word, word_list, visited, result):\n",
    "    if source_word == target_word:\n",
    "        return True\n",
    "\n",
    "    for idx, word in enumerate(word_list):\n",
    "        if visited[idx] is True or is_word_similar(source_word, word) is False:\n",
    "            continue\n",
    "\n",
    "        visited[idx] = True\n",
    "        result.append(word)\n",
    "        if transform(word, target_word, word_list, visited, result) is True:\n",
    "            return True\n",
    "        else:\n",
    "            result.pop(-1)\n",
    "            # visited[idx] = False\n",
    "\n",
    "    return False\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "\n",
    "        result = [beginWord]\n",
    "        if transform(beginWord, endWord, wordList, [False] * len(wordList), result):\n",
    "            return result\n",
    "        else:\n",
    "            return []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "def is_word_similar(word1, word2):\n",
    "    diff_letter_count = 0\n",
    "    for i in range(len(word1)):\n",
    "        if word1[i] != word2[i]:\n",
    "            diff_letter_count += 1\n",
    "        if diff_letter_count >= 2:\n",
    "            return False\n",
    "\n",
    "    if diff_letter_count == 0:\n",
    "        return False\n",
    "    return True\n",
    "\n",
    "\n",
    "def transform(source_word, target_word, word_list, visited, result):\n",
    "    if source_word == target_word:\n",
    "        return True\n",
    "\n",
    "    for idx, word in enumerate(word_list):\n",
    "        if visited[idx] is True or is_word_similar(source_word, word) is False:\n",
    "            continue\n",
    "\n",
    "        visited[idx] = True\n",
    "        result.append(word)\n",
    "        if transform(word, target_word, word_list, visited, result) is True:\n",
    "            return True\n",
    "        else:\n",
    "            result.pop(-1)\n",
    "            # visited[idx] = False\n",
    "\n",
    "    return False\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "\n",
    "        result = [beginWord]\n",
    "        wordList = sorted(wordList, reverse=True)\n",
    "        if transform(beginWord, endWord, wordList, [False] * len(wordList), result):\n",
    "            return result\n",
    "        else:\n",
    "            return []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "def is_word_similar(word1, word2):\n",
    "    diff_letter_count = 0\n",
    "    for i in range(len(word1)):\n",
    "        if word1[i] != word2[i]:\n",
    "            diff_letter_count += 1\n",
    "        if diff_letter_count >= 2:\n",
    "            return False\n",
    "\n",
    "    if diff_letter_count == 0:\n",
    "        return False\n",
    "    return True\n",
    "\n",
    "\n",
    "def transform(source_word, target_word, word_list, visited, result):\n",
    "    if source_word == target_word:\n",
    "        return True\n",
    "\n",
    "    for idx, word in enumerate(word_list):\n",
    "        if visited[idx] is True or is_word_similar(source_word, word) is False:\n",
    "            continue\n",
    "\n",
    "        visited[idx] = True\n",
    "        result.append(word)\n",
    "        if transform(word, target_word, word_list, visited, result) is True:\n",
    "            return True\n",
    "        else:\n",
    "            result.pop(-1)\n",
    "            # visited[idx] = False\n",
    "\n",
    "    return False\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "\n",
    "        result = [beginWord]\n",
    "        wordList = sorted(wordList)\n",
    "        if transform(beginWord, endWord, wordList, [False] * len(wordList), result):\n",
    "            return result\n",
    "        else:\n",
    "            return []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "\"\"\"\n",
    "\"hit\"\n",
    "\"hit\"\n",
    "[\"hit\"]\n",
    "\n",
    "\"hit\"\n",
    "\"cog\"\n",
    "[\"hot\",\"dot\",\"dog\",\"lot\",\"log\",\"cog\"]\n",
    "\n",
    "\"hit\"\n",
    "\"cog\"\n",
    "[\"hot\",\"dot\",\"dog\",\"lot\",\"log\"]\n",
    "\n",
    "\"hot\"\n",
    "\"dog\"\n",
    "[\"hot\",\"dog\"]\n",
    "\n",
    "\"qa\"\n",
    "\"sq\"\n",
    "[\"si\",\"go\",\"se\",\"cm\",\"so\",\"ph\",\"mt\",\"db\",\"mb\",\"sb\",\"kr\",\"ln\",\"tm\",\"le\",\"av\",\"sm\",\"ar\",\"ci\",\"ca\",\"br\",\"ti\",\"ba\",\"to\",\"ra\",\"fa\",\"yo\",\"ow\",\"sn\",\"ya\",\"cr\",\"po\",\"fe\",\"ho\",\"ma\",\"re\",\"or\",\"rn\",\"au\",\"ur\",\"rh\",\"sr\",\"tc\",\"lt\",\"lo\",\"as\",\"fr\",\"nb\",\"yb\",\"if\",\"pb\",\"ge\",\"th\",\"pm\",\"rb\",\"sh\",\"co\",\"ga\",\"li\",\"ha\",\"hz\",\"no\",\"bi\",\"di\",\"hi\",\"qa\",\"pi\",\"os\",\"uh\",\"wm\",\"an\",\"me\",\"mo\",\"na\",\"la\",\"st\",\"er\",\"sc\",\"ne\",\"mn\",\"mi\",\"am\",\"ex\",\"pt\",\"io\",\"be\",\"fm\",\"ta\",\"tb\",\"ni\",\"mr\",\"pa\",\"he\",\"lr\",\"sq\",\"ye\"]\n",
    "\"\"\"\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        wordSet = set(wordList)\n",
    "        if endWord not in wordSet: return []\n",
    "        if beginWord == endWord: return [beginWord]\n",
    "\n",
    "        wordSet.discard(beginWord)\n",
    "        path = [beginWord]\n",
    "        solved = [False]\n",
    "        self.dfs(wordSet, beginWord, endWord, path, solved)\n",
    "        if solved[0]: return path\n",
    "        return []\n",
    "    def dfs(self, wordSet, word, endWord, path, solved):\n",
    "        if word == endWord:\n",
    "            solved[0] = True\n",
    "            return\n",
    "        for nextWord in self.getNext(word, wordSet):\n",
    "            wordSet.discard(nextWord)\n",
    "            path.append(nextWord)\n",
    "            self.dfs(wordSet, nextWord, endWord, path, solved)\n",
    "            if not solved[0]:\n",
    "                path.pop()\n",
    "            else:\n",
    "                break\n",
    "    def getNext(self, word, wordSet):\n",
    "        charList = list(word)\n",
    "        res = []\n",
    "        for i in range(len(charList)):\n",
    "            charListCopy = charList[:]\n",
    "            for _a in range(26):\n",
    "                a = chr(ord('a')+_a)\n",
    "                if charListCopy[i] == a: continue\n",
    "                charListCopy[i] = a\n",
    "                _word = ''.join(charListCopy)\n",
    "                if _word in wordSet:\n",
    "                    res.append(_word)\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        def dfs(cur, end, path):\n",
    "            nonlocal ans\n",
    "            if cur == end:\n",
    "                ans = path[:]\n",
    "                return\n",
    "            for s in wordList:\n",
    "                if s != cur and s not in vis and sum(cur[i] != s[i] for i in range(len(s))) == 1:\n",
    "                    vis.add(s)\n",
    "                    path.append(s)\n",
    "                    dfs(s, end, path)\n",
    "                    path.pop()\n",
    "                    # vis.remove(s)\n",
    "\n",
    "        vis = set()\n",
    "        ans = []\n",
    "        dfs(beginWord, endWord, [beginWord])\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        s=set(wordList)\n",
    "        ans=[]\n",
    "        v=set()\n",
    "\n",
    "        def diff(a,b):\n",
    "            res=0\n",
    "            for c0,c1 in zip(a,b):\n",
    "                if c0!=c1:\n",
    "                    res+=1\n",
    "            return res\n",
    "\n",
    "        def dfs(p):\n",
    "            ans.append(p)\n",
    "            v.add(p)\n",
    "            if p==endWord:\n",
    "                return True\n",
    "            for x in s:\n",
    "                if diff(x,p)==1 and x not in v:\n",
    "                    if dfs(x):\n",
    "                        return True\n",
    "            ans.pop()\n",
    "        dfs(beginWord)\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        word_set = set(wordList)\n",
    "        if endWord not in word_set:\n",
    "            return []\n",
    "        if beginWord not in word_set:\n",
    "            wordList.append(beginWord)\n",
    "            word_set.add(beginWord)\n",
    "        n = len(wordList)\n",
    "        word_pos = {wordList[i]: i for i in range(n)}\n",
    "        next_words = [[] for _ in range(n)]\n",
    "        for i in range(n):\n",
    "            for j in range(len(wordList[i])):\n",
    "                for k in range(26):\n",
    "                    if ord(wordList[i][j]) - ord(\"a\") != k:\n",
    "                        next_word = (\n",
    "                            wordList[i][:j] + chr(k + ord(\"a\")) + wordList[i][j + 1 :]\n",
    "                        )\n",
    "                        if next_word in word_set:\n",
    "                            next_words[i].append(next_word)\n",
    "        q, head = [beginWord], -1\n",
    "        levels = [0]\n",
    "        prev_pos = [[]]\n",
    "        q_pos = {beginWord: 0}\n",
    "        while head < len(q) - 1:\n",
    "            head += 1\n",
    "            word = q[head]\n",
    "            for next_word in next_words[word_pos[word]]:\n",
    "                if next_word not in q_pos:\n",
    "                    q_pos[next_word] = len(q)\n",
    "                    prev_pos.append([])\n",
    "                    prev_pos[-1].append(head)\n",
    "                    q.append(next_word)\n",
    "                    levels.append(levels[head] + 1)\n",
    "                else:\n",
    "                    pos = q_pos[next_word]\n",
    "                    if levels[pos] > levels[head]:\n",
    "                        prev_pos[pos].append(head)\n",
    "        if endWord not in q_pos:\n",
    "            return []\n",
    "        return self.search_path(q, prev_pos, q_pos[endWord], [])[0]\n",
    "\n",
    "    def search_path(\n",
    "        self, q: List[str], prev_pos: List[List[int]], pos: int, path: List[str]\n",
    "    ) -> List[List[str]]:\n",
    "        paths = []\n",
    "        if pos == 0:\n",
    "            temp_path = path + [q[pos]]\n",
    "            temp_path.reverse()\n",
    "            paths.append(temp_path)\n",
    "            return paths\n",
    "        for p in prev_pos[pos]:\n",
    "            paths.extend(self.search_path(q, prev_pos, p, path + [q[pos]]))\n",
    "        return paths"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from typing import List\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        wordList.append(beginWord)\n",
    "        graph = [[] for i in range(len(wordList))]\n",
    "        end_index = None\n",
    "        for i in range(len(wordList)):\n",
    "            if wordList[i] == endWord:\n",
    "                end_index = i\n",
    "            for j in range(i + 1, len(wordList)):\n",
    "                if self.diff(wordList[i], wordList[j]):\n",
    "                    graph[i].append(j)\n",
    "                    graph[j].append(i)\n",
    "        if end_index is None:\n",
    "            return []\n",
    "        used = set()\n",
    "        path = self.dfs(graph, len(graph) - 1, end_index, [len(graph) - 1], used)\n",
    "        if not path:\n",
    "            return []\n",
    "        return [wordList[path[i]] for i in range(len(path))]\n",
    "\n",
    "\n",
    "    def dfs(self, graph, start, end, path, used):\n",
    "        if start == end:\n",
    "            return path\n",
    "        used.add(start)\n",
    "        for i in range(len(graph[start])):\n",
    "            if graph[start][i] in used:\n",
    "                continue\n",
    "            path.append(graph[start][i])\n",
    "            res = self.dfs(graph, graph[start][i], end, path, used)\n",
    "            if res:\n",
    "                return res\n",
    "            path.pop()\n",
    "\n",
    "    def diff(self, a, b):\n",
    "        count = 0\n",
    "        for i in range(len(a)):\n",
    "            if a[i] != b[i]:\n",
    "                count += 1\n",
    "            if count >= 2:\n",
    "                return False\n",
    "        return True if count == 1 else False\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        hashmap = collections.defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(word)):\n",
    "                hashmap[word[:i] + '*' + word[i+1:]].append(word)\n",
    "        q = collections.deque([beginWord])\n",
    "        #q.append(beginWord)\n",
    "        w_dict = {beginWord:[beginWord]}\n",
    "        while q:\n",
    "            word = q.popleft()\n",
    "            if word == endWord:\n",
    "                return w_dict[word]\n",
    "            for i in range(len(word)):\n",
    "                if word[:i] + '*' + word[i + 1:] in hashmap:\n",
    "                    for tmp in hashmap[word[:i] + '*' + word[i + 1:]]:\n",
    "                        if tmp not in w_dict:\n",
    "                            w_dict[tmp] = w_dict[word] + [tmp]\n",
    "                            q.append(tmp)\n",
    "\n",
    "        return []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        hashMap = collections.defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(word)):\n",
    "                hashMap[word[:i] + '*' + word[i+1:]].append(word)\n",
    "\n",
    "        dq = collections.deque([beginWord])\n",
    "        res = {beginWord: [beginWord]}\n",
    "        while dq:\n",
    "            word = dq.popleft()\n",
    "            if word == endWord:\n",
    "                return res[word]\n",
    "            for i in range(len(word)):\n",
    "                if word[:i] + '*' + word[i+1:] in hashMap.keys():\n",
    "                    for temp in hashMap[word[:i] + '*' + word[i+1:]]:\n",
    "                        if temp not in res.keys():\n",
    "                            res[temp] = res[word] + [temp]\n",
    "                            dq.append(temp)\n",
    "\n",
    "        return []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from typing import List\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        for i in range(len(wordList)):\n",
    "            if wordList[i] == endWord:\n",
    "                end_index = i\n",
    "                break\n",
    "        else:\n",
    "            return []\n",
    "        wordList.append(beginWord)\n",
    "        graph = [[] for i in range(len(wordList))]\n",
    "        for i in range(len(wordList)):\n",
    "            for j in range(i + 1, len(wordList)):\n",
    "                if self.diff(wordList[i], wordList[j]):\n",
    "                    graph[i].append(j)\n",
    "                    graph[j].append(i)\n",
    "        used = set()\n",
    "        path = self.dfs(graph, len(graph) - 1, end_index, [len(graph) - 1], used)\n",
    "        if not path:\n",
    "            return []\n",
    "        return [wordList[path[i]] for i in range(len(path))]\n",
    "\n",
    "\n",
    "    def dfs(self, graph, start, end, path, used):\n",
    "        if start == end:\n",
    "            return path\n",
    "        used.add(start)\n",
    "        for i in range(len(graph[start])):\n",
    "            if graph[start][i] in used:\n",
    "                continue\n",
    "            path.append(graph[start][i])\n",
    "            res = self.dfs(graph, graph[start][i], end, path, used)\n",
    "            if res:\n",
    "                return res\n",
    "            path.pop()\n",
    "\n",
    "    def diff(self, a, b):\n",
    "        count = 0\n",
    "        for i in range(len(a)):\n",
    "            if a[i] != b[i]:\n",
    "                count += 1\n",
    "            if count >= 2:\n",
    "                return False\n",
    "        return True if count == 1 else False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        hashmap = collections.defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(word)):\n",
    "                hashmap[word[:i] + '*' + word[i+1:]].append(word)\n",
    "        q = collections.deque([beginWord])\n",
    "        #q.append(beginWord)\n",
    "        w_dict = {beginWord:[beginWord]}\n",
    "        while q:\n",
    "            word = q.popleft()\n",
    "            if word == endWord:\n",
    "                return w_dict[word]\n",
    "            for i in range(len(word)):\n",
    "                if word[:i] + '*' + word[i + 1:] in hashmap:\n",
    "                    for tmp in hashmap[word[:i] + '*' + word[i + 1:]]:\n",
    "                        if tmp not in w_dict:\n",
    "                            w_dict[tmp] = w_dict[word] + [tmp]\n",
    "                            q.append(tmp)\n",
    "\n",
    "        return []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "        \n",
    "        wordDict = dict.fromkeys(wordList)\n",
    "\n",
    "        def backtracing(path: List, res: List, used: int) -> bool: \n",
    "            # print(path)\n",
    "            if path[-1] == endWord:\n",
    "                res.append(list(path))\n",
    "                return True\n",
    "\n",
    "            if path[-1] in visited:\n",
    "                return False \n",
    "            visited.add(path[-1])\n",
    "\n",
    "            for ri in range(len(path[-1])):\n",
    "                for c in 'abcdefghijklmnopqrstuvwxyz': \n",
    "                    w = path[-1][0:ri] + c + path[-1][ri+1: ]\n",
    "                    if w not in wordDict:\n",
    "                        continue \n",
    "\n",
    "                    path.append(w)\n",
    "                    if backtracing(path, res, used) == True:\n",
    "                        return True \n",
    "                    path.pop()\n",
    "\n",
    "            return False \n",
    "           \n",
    "        res = []\n",
    "        used = 0\n",
    "        visited = set()\n",
    "        flag = backtracing([beginWord], res, used)\n",
    "        # print(res)\n",
    "        return res[0] if res else []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:\n",
    "        wordList.append(beginWord)\n",
    "        ### 构建具有邻接关系的桶\n",
    "        buckets = defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(beginWord)):\n",
    "                match = word[:i] + '_' + word[i+1:]\n",
    "                buckets[match].append(word)\n",
    "        ##### BFS遍历\n",
    "        preWords = defaultdict(list)  # 前溯词列表\n",
    "        toSeen = deque([(beginWord, 1)])  # 待遍历词及深度\n",
    "        beFound = {beginWord:1}  # 已探测词列表\n",
    "        while toSeen:\n",
    "            curWord, level = toSeen.popleft()\n",
    "            for i in range(len(beginWord)):\n",
    "                match = curWord[:i] + '_' + curWord[i+1:]\n",
    "                for word in buckets[match]:\n",
    "                    if word not in beFound:\n",
    "                        beFound[word] = level+1\n",
    "                        toSeen.append((word, level+1))\n",
    "                    if beFound[word] == level+1:  # 当前深度等于该词首次遍历深度，则仍应加入前溯词列表\n",
    "                        preWords[word].append(curWord)\n",
    "            if endWord in beFound and level+1 > beFound[endWord]:  # 已搜索到目标词，且完成当前层遍历\n",
    "                break\n",
    "        #### 列表推导式输出结果\n",
    "        if endWord in beFound:\n",
    "            res = [[endWord]]\n",
    "            while res[0][0] != beginWord:\n",
    "                res = [[word] + r for r in res for word in preWords[r[0]]] \n",
    "            return res[0]\n",
    "        else:\n",
    "            return []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "        \n",
    "        wordDict = dict.fromkeys(wordList)\n",
    "\n",
    "        def backtracing(path: List, res: List, used: int) -> bool: \n",
    "            # print(path)\n",
    "            if path[-1] == endWord:\n",
    "                res.append(list(path))\n",
    "                return True\n",
    "\n",
    "            if path[-1] in visited:\n",
    "                return False \n",
    "            visited.add(path[-1])\n",
    "\n",
    "            for ri in range(len(path[-1])):\n",
    "                for c in 'abcdefghijklmnopqrstuvwxyz': \n",
    "                    w = path[-1][0:ri] + c + path[-1][ri+1: ]\n",
    "                    if w not in wordDict:\n",
    "                        continue \n",
    "\n",
    "                    path.append(w)\n",
    "                    if backtracing(path, res, used) == True:\n",
    "                        return True \n",
    "                    path.pop()\n",
    "\n",
    "            return False \n",
    "           \n",
    "        res = []\n",
    "        used = 0\n",
    "        visited = set()\n",
    "        flag = backtracing([beginWord], res, used)\n",
    "        # print(res)\n",
    "        return res[0] if res else []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        # BFS\n",
    "        hashmap = collections.defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(word)):\n",
    "                hashmap[word[:i] + '*' + word[i + 1:]].append(word)\n",
    "        queue = collections.deque([beginWord])\n",
    "        w_dict = {beginWord: [beginWord]}\n",
    "        while queue:\n",
    "            word = queue.popleft()\n",
    "            if word == endWord:\n",
    "                return w_dict[word]\n",
    "            for i in range(len(word)):\n",
    "                if word[:i] + '*' + word[i + 1:] in hashmap:\n",
    "                    for tmp in hashmap[word[:i] + '*' + word[i + 1:]]:\n",
    "                        if tmp not in w_dict:\n",
    "                            w_dict[tmp] = w_dict[word] + [tmp]\n",
    "                            queue.append(tmp)\n",
    "        return []\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        # BFS\n",
    "        hashmap = collections.defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(word)):\n",
    "                hashmap[word[:i] + '*' + word[i + 1:]].append(word)\n",
    "        queue = collections.deque([beginWord])\n",
    "        w_dict = {beginWord: [beginWord]}\n",
    "        while queue:\n",
    "            word = queue.popleft()\n",
    "            if word == endWord:\n",
    "                return w_dict[word]\n",
    "            for i in range(len(word)):\n",
    "                if word[:i] + '*' + word[i + 1:] in hashmap:\n",
    "                    for tmp in hashmap[word[:i] + '*' + word[i + 1:]]:\n",
    "                        if tmp not in w_dict:\n",
    "                            w_dict[tmp] = w_dict[word] + [tmp]\n",
    "                            queue.append(tmp)\n",
    "        return []\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        dic = collections.defaultdict(list)\n",
    "        for a in wordList:\n",
    "            for i in range(len(a)):\n",
    "                s = a[0:i] + '*' + a[i+1:]\n",
    "                dic[s].append(a)\n",
    "        \n",
    "        qe = collections.deque([beginWord])\n",
    "\n",
    "\n",
    "        w_dict = {beginWord: [beginWord]}\n",
    "        while qe:\n",
    "            a = qe.popleft()\n",
    "            if a == endWord:\n",
    "                return w_dict[a]\n",
    "            for i in range(len(a)):\n",
    "                s = a[0:i] + '*' + a[i+1:]\n",
    "                if s in dic:\n",
    "                    for tmp in dic[s]:\n",
    "                        if tmp not in w_dict:\n",
    "                            w_dict[tmp] = w_dict[a] + [tmp]\n",
    "                            qe.append(tmp)\n",
    "        return []\n",
    "                    \n",
    "            \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        # DFS\n",
    "        hashmap = collections.defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(word)):\n",
    "                hashmap[word[:i] + '*' + word[i + 1:]].append(word)\n",
    "        stack = [beginWord]\n",
    "        w_dict = {beginWord: [beginWord]}\n",
    "        while stack:\n",
    "            word = stack.pop()\n",
    "            if word == endWord:\n",
    "                return w_dict[word]\n",
    "            for i in range(len(word)):\n",
    "                if word[:i] + '*' + word[i + 1:] in hashmap:\n",
    "                    for tmp in hashmap[word[:i] + '*' + word[i + 1:]]:\n",
    "                        if tmp not in w_dict:\n",
    "                            w_dict[tmp] = w_dict[word] + [tmp]\n",
    "                            stack.append(tmp)\n",
    "        return []\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        # BFS\n",
    "        hashmap = collections.defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(word)):\n",
    "                hashmap[word[:i] + '*' + word[i + 1:]].append(word)\n",
    "        queue = collections.deque([beginWord])\n",
    "        w_dict = {beginWord: [beginWord]}\n",
    "        while queue:\n",
    "            word = queue.popleft()\n",
    "            if word == endWord:\n",
    "                return w_dict[word]\n",
    "            for i in range(len(word)):\n",
    "                if word[:i] + '*' + word[i + 1:] in hashmap:\n",
    "                    for tmp in hashmap[word[:i] + '*' + word[i + 1:]]:\n",
    "                        if tmp not in w_dict:\n",
    "                            w_dict[tmp] = w_dict[word] + [tmp]\n",
    "                            queue.append(tmp)\n",
    "        return []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        hashmap = collections.defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(word)):\n",
    "                hashmap[word[:i] + '*' + word[i + 1:]].append(word)\n",
    "        queue = collections.deque([beginWord])\n",
    "        w_dict = {beginWord: [beginWord]}\n",
    "        while queue:\n",
    "            word = queue.popleft()\n",
    "            if word == endWord:\n",
    "                return w_dict[word]\n",
    "            for i in range(len(word)):\n",
    "                if word[:i] + '*' + word[i + 1:] in hashmap:\n",
    "                    for tmp in hashmap[word[:i] + '*' + word[i + 1:]]:\n",
    "                        if tmp not in w_dict:\n",
    "                            w_dict[tmp] = w_dict[word] + [tmp]\n",
    "                            queue.append(tmp)\n",
    "        return []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import defaultdict\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "        if beginWord == endWord:\n",
    "            return [beginWord]\n",
    "        d = defaultdict(list)\n",
    "        for i,w in enumerate(wordList):\n",
    "            for j,c in enumerate(w):\n",
    "                d[w[:j] + '*' + w[j+1:]].append(i)\n",
    "        # print(d)\n",
    "        q = [(beginWord,-1)]\n",
    "        s = set()\n",
    "        for i,(w,_) in enumerate(q):\n",
    "            if w == endWord:\n",
    "                break\n",
    "            for j,c in enumerate(w):\n",
    "                for v in d[w[:j] + '*' + w[j+1:]]:\n",
    "                    if v not in s:\n",
    "                        q.append((wordList[v],i))\n",
    "                        s.add(v)\n",
    "        if w != endWord:\n",
    "            return []\n",
    "        ans = []\n",
    "        while i != -1:\n",
    "            ans.append(q[i][0])\n",
    "            i = q[i][1]\n",
    "        return ans[::-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, bb: str, aa: str, wc: List[str]) -> List[str]:  \n",
    "        \n",
    "        def g(s1,s2):\n",
    "            a=False\n",
    "            if len(s1)==1:\n",
    "                return s1!=s2\n",
    "            for x,y in zip(s1,s2):\n",
    "              \n",
    "                if x==y:\n",
    "                    continue\n",
    "                else:\n",
    "                   if a:\n",
    "                     return False\n",
    "                   a=True  \n",
    "            return s1!=s2 and True            \n",
    "       \n",
    "       \n",
    "        e=[[] for _ in range(len(wc))]\n",
    "        for i in range(len(wc)):\n",
    "           for j in range(i+1,len(wc)):\n",
    "               if g(wc[i],wc[j]):\n",
    "                   e[i].append(j)\n",
    "                   e[j].append(i)\n",
    "        print(e)          \n",
    "             \n",
    "        q=[]\n",
    "        for i in range(len(wc)):\n",
    "           if g(wc[i],bb):\n",
    "              q.append(i)  \n",
    "        vis=set()\n",
    "        v1=set()\n",
    "        s=[bb]\n",
    "        ans=[]\n",
    "        ok=False\n",
    "        \n",
    "        def f(q):\n",
    "          nonlocal s,ok\n",
    "          if ok:\n",
    "              return      \n",
    "          for c in q:\n",
    "             if c in vis or c in v1:\n",
    "               continue\n",
    "             if wc[c]==aa:\n",
    "                 s.append(wc[c])\n",
    "                 ans.append(s.copy())\n",
    "                 s.pop()\n",
    "                 ok=True\n",
    "                 return    \n",
    "             s.append(wc[c])\n",
    "             vis.add(c)\n",
    "            #  print(e[c],s)\n",
    "             f(e[c])\n",
    "             s.pop()\n",
    "             vis.remove(c)\n",
    "             v1.add(c)\n",
    "          return   \n",
    "        f(q)\n",
    "        if len(ans)>0:\n",
    "            return  ans[0]\n",
    "        else:\n",
    "            return []    \n",
    "              "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        word_dict = {word: 0 for word in wordList}\n",
    "        result = []\n",
    "        if endWord not in word_dict:\n",
    "            return result\n",
    "\n",
    "        template_words_dict = defaultdict(list)\n",
    "        word_template_dict = defaultdict(list)\n",
    "        for word in wordList:\n",
    "            char_list = list(word)\n",
    "            for idx, char in enumerate(char_list):\n",
    "                char_list[idx] = \"*\"\n",
    "                template = \"\".join(char_list)\n",
    "                char_list[idx] = char\n",
    "                template_words_dict[template].append(word)\n",
    "                word_template_dict[word].append(template)\n",
    "\n",
    "        q = deque([[beginWord]])\n",
    "        while q:\n",
    "            _result = q.popleft()\n",
    "            if _result[-1] == endWord:\n",
    "                return _result\n",
    "            char_list = list(_result[-1])\n",
    "            for idx, char in enumerate(char_list):\n",
    "                char_list[idx] = \"*\"\n",
    "                template = \"\".join(char_list)\n",
    "                char_list[idx] = char\n",
    "                for _word in template_words_dict[template]:\n",
    "                    if _word == _result[-1]:\n",
    "                        continue\n",
    "                    q.append(_result + [_word])\n",
    "                if template_words_dict[template]:\n",
    "                    template_words_dict[template].pop()\n",
    "\n",
    "        return []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        \n",
    "        word2num = {}\n",
    "        head = {}\n",
    "        edge = []\n",
    "        num = 0\n",
    "\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "\n",
    "        def addedge(Word1: str, Word2: str):\n",
    "            nonlocal num\n",
    "            if Word1 not in head: head[Word1] = -1\n",
    "            if Word2 not in head: head[Word2] = -1\n",
    "            edge.append([Word2, head[Word1]])\n",
    "            head[Word1] = num\n",
    "            edge.append([Word1, head[Word2]])\n",
    "            head[Word2] = num + 1\n",
    "            num = num + 2\n",
    "\n",
    "        def addwords(Word: str):\n",
    "            length = len(Word)\n",
    "            for i in range(length):\n",
    "                tempword = Word[:i] + \"*\" + Word[i+1:]\n",
    "                addedge(Word, tempword)\n",
    "\n",
    "        def bfs(beginWord: str, endWord: str):\n",
    "            queue = [beginWord]\n",
    "            vis = {}\n",
    "            pre = {}\n",
    "            while len(queue) > 0:\n",
    "                front = queue.pop()\n",
    "                heads = head[front]\n",
    "                while heads != -1:\n",
    "                    to = edge[heads][0]\n",
    "                    if to not in vis:\n",
    "                        vis[to] = True\n",
    "                        pre[to] = front\n",
    "                        queue.append(to) \n",
    "                    if to == endWord:\n",
    "                        return pre\n",
    "                    heads = edge[heads][-1]\n",
    "            return None\n",
    "\n",
    "        addwords(beginWord)\n",
    "        for each in wordList:\n",
    "            addwords(each)\n",
    "\n",
    "        pre = bfs(beginWord, endWord)\n",
    "        if pre == None:\n",
    "            return []\n",
    "        \n",
    "        path = [endWord]\n",
    "        point = endWord\n",
    "        while point != beginWord:\n",
    "            point = pre[pre[point]]\n",
    "            path.append(point)\n",
    "        path.reverse()\n",
    "        \n",
    "        return path"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        # DFS\n",
    "        hashmap = collections.defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(word)):\n",
    "                hashmap[word[:i] + '*' + word[i + 1:]].append(word)\n",
    "        stack = [beginWord]\n",
    "        w_dict = {beginWord: [beginWord]}\n",
    "        while stack:\n",
    "            word = stack.pop()\n",
    "            if word == endWord:\n",
    "                return w_dict[word]\n",
    "            for i in range(len(word)):\n",
    "                if word[:i] + '*' + word[i + 1:] in hashmap:\n",
    "                    for tmp in hashmap[word[:i] + '*' + word[i + 1:]]:\n",
    "                        if tmp not in w_dict:\n",
    "                            w_dict[tmp] = w_dict[word] + [tmp]\n",
    "                            stack.append(tmp)\n",
    "        return []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "\tdef findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "\t\t# DFS\n",
    "\t\thashmap = collections.defaultdict(list)\n",
    "\t\tfor word in wordList:\n",
    "\t\t\tfor i in range(len(word)):\n",
    "\t\t\t\thashmap[word[:i] + '*' + word[i + 1:]].append(word)\n",
    "\t\tstack = [beginWord]\n",
    "\t\tw_dict = {beginWord: [beginWord]}\n",
    "\t\twhile stack:\n",
    "\t\t\tword = stack.pop()\n",
    "\t\t\tif word == endWord:\n",
    "\t\t\t\treturn w_dict[word]\n",
    "\t\t\tfor i in range(len(word)):\n",
    "\t\t\t\tif word[:i] + '*' + word[i + 1:] in hashmap:\n",
    "\t\t\t\t\tfor tmp in hashmap[word[:i] + '*' + word[i + 1:]]:\n",
    "\t\t\t\t\t\tif tmp not in w_dict:\n",
    "\t\t\t\t\t\t\tw_dict[tmp] = w_dict[word] + [tmp]\n",
    "\t\t\t\t\t\t\tstack.append(tmp)\n",
    "\t\treturn []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        wordDict = dict.fromkeys(wordList)\n",
    "\n",
    "        def dfs(path, res, visited) -> bool:\n",
    "            if path[-1] == endWord:\n",
    "                res.append(list(path))\n",
    "                return True\n",
    "            \n",
    "            if path[-1] in visited:\n",
    "                return False \n",
    "            else:\n",
    "                visited.add(path[-1])\n",
    "\n",
    "            for i in range(len(path[-1])):\n",
    "                for alpha in 'qwertyuiopasdfghjklzxcvbnm':\n",
    "                    new = path[-1][0: i] + alpha + path[-1][i+1: ]\n",
    "                        \n",
    "                    if new in wordDict:\n",
    "                        if dfs(path+[new], res, visited) == True:\n",
    "                            return True \n",
    "            \n",
    "            return False \n",
    "        \n",
    "        res = []\n",
    "        visited = set()\n",
    "        dfs([beginWord, ], res, visited)\n",
    "        # print(res)\n",
    "        return res[0] if res else []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        # DFS\n",
    "        hashmap = collections.defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(word)):\n",
    "                hashmap[word[:i] + '*' + word[i + 1:]].append(word)\n",
    "        stack = [beginWord]\n",
    "        w_dict = {beginWord: [beginWord]}\n",
    "        while stack:\n",
    "            word = stack.pop()\n",
    "            if word == endWord:\n",
    "                return w_dict[word]\n",
    "            for i in range(len(word)):\n",
    "                if word[:i] + '*' + word[i + 1:] in hashmap:\n",
    "                    for tmp in hashmap[word[:i] + '*' + word[i + 1:]]:\n",
    "                        if tmp not in w_dict:\n",
    "                            w_dict[tmp] = w_dict[word] + [tmp]\n",
    "                            stack.append(tmp)\n",
    "        return []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        # DFS\n",
    "        hashmap = collections.defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(word)):\n",
    "                hashmap[word[:i] + '*' + word[i + 1:]].append(word)\n",
    "        stack = [beginWord]\n",
    "        w_dict = {beginWord: [beginWord]}\n",
    "        while stack:\n",
    "            word = stack.pop()\n",
    "            if word == endWord:\n",
    "                return w_dict[word]\n",
    "            for i in range(len(word)):\n",
    "                if word[:i] + '*' + word[i + 1:] in hashmap:\n",
    "                    for tmp in hashmap[word[:i] + '*' + word[i + 1:]]:\n",
    "                        if tmp not in w_dict:\n",
    "                            w_dict[tmp] = w_dict[word] + [tmp]\n",
    "                            stack.append(tmp)\n",
    "        return []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        wordDict = dict.fromkeys(wordList)\n",
    "\n",
    "        def dfs(path, res, visited) -> bool:\n",
    "            if path[-1] == endWord:\n",
    "                res.append(list(path))\n",
    "                return True\n",
    "            \n",
    "            if path[-1] in visited:\n",
    "                return False \n",
    "            else:\n",
    "                visited.add(path[-1])\n",
    "\n",
    "            for i in range(len(path[-1])):\n",
    "                for alpha in 'qwertyuiopasdfghjklzxcvbnm':\n",
    "                    new = path[-1][0: i] + alpha + path[-1][i+1: ]\n",
    "                    if new in path:\n",
    "                        continue \n",
    "                        \n",
    "                    if new in wordDict:\n",
    "                        if dfs(path+[new], res, visited) == True:\n",
    "                            return True \n",
    "            \n",
    "            return False \n",
    "        \n",
    "        res = []\n",
    "        visited = set()\n",
    "        dfs([beginWord, ], res, visited)\n",
    "        # print(res)\n",
    "        return res[0] if res else []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        hashmap=collections.defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(word)):\n",
    "                hashmap[word[:i]+'*'+word[i+1:]].append(word)\n",
    "        stack=[beginWord]\n",
    "        w_dict={beginWord:[beginWord]}\n",
    "        while stack:\n",
    "            word=stack.pop()\n",
    "            if word==endWord:\n",
    "                return w_dict[word]\n",
    "            for i in range(len(word)):\n",
    "                if word[:i]+'*'+word[i+1:] in hashmap:\n",
    "                    for tmp in hashmap[word[:i]+'*'+word[i+1:]]:\n",
    "                        if tmp not in w_dict:\n",
    "                            w_dict[tmp]=w_dict[word]+[tmp]\n",
    "                            stack.append(tmp)\n",
    "        return []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        # DFS\n",
    "        hashmap = collections.defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(word)):\n",
    "                hashmap[word[:i] + '*' + word[i + 1:]].append(word)\n",
    "        stack = [beginWord]\n",
    "        w_dict = {beginWord: [beginWord]}\n",
    "        while stack:\n",
    "            word = stack.pop()\n",
    "            if word == endWord:\n",
    "                return w_dict[word]\n",
    "            for i in range(len(word)):\n",
    "                if word[:i] + '*' + word[i + 1:] in hashmap:\n",
    "                    for tmp in hashmap[word[:i] + '*' + word[i + 1:]]:\n",
    "                        if tmp not in w_dict:\n",
    "                            w_dict[tmp] = w_dict[word] + [tmp]\n",
    "                            stack.append(tmp)\n",
    "        return []\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        wordDict = dict.fromkeys(wordList)\n",
    "\n",
    "        def dfs(path, res, visited) -> bool:\n",
    "            if path[-1] == endWord:\n",
    "                res.append(list(path))\n",
    "                return True\n",
    "            \n",
    "            if path[-1] in visited:\n",
    "                return False \n",
    "            else:\n",
    "                visited.add(path[-1])\n",
    "\n",
    "            for i in range(len(path[-1])):\n",
    "                for alpha in 'qwertyuiopasdfghjklzxcvbnm':\n",
    "                    new = path[-1][0: i] + alpha + path[-1][i+1: ]\n",
    "\n",
    "                    if new in wordDict:\n",
    "                        if dfs(path+[new], res, visited) == True:\n",
    "                            return True \n",
    "            \n",
    "            return False \n",
    "        \n",
    "        res = []\n",
    "        visited = set()\n",
    "        dfs([beginWord, ], res, visited)\n",
    "        # print(res)\n",
    "        return res[0] if res else []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        wordDict = dict.fromkeys(wordList)\n",
    "\n",
    "        def dfs(path, res, visited) -> bool:\n",
    "            if path[-1] == endWord:\n",
    "                res.append(list(path))\n",
    "                return True\n",
    "            \n",
    "            if path[-1] in visited:\n",
    "                return False \n",
    "            else:\n",
    "                visited.add(path[-1])\n",
    "\n",
    "            for i in range(len(path[-1])):\n",
    "                for alpha in 'qwertyuiopasdfghjklzxcvbnm':\n",
    "                    new = path[-1][0: i] + alpha + path[-1][i+1: ]\n",
    "                    if new in path:\n",
    "                        continue \n",
    "                        \n",
    "                    if new in wordDict:\n",
    "                        if dfs(path+[new], res, visited) == True:\n",
    "                            return True \n",
    "            \n",
    "            return False \n",
    "        \n",
    "        res = []\n",
    "        visited = set()\n",
    "        dfs([beginWord, ], res, visited)\n",
    "        # print(res)\n",
    "        return res[0] if res else []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        # DFS\n",
    "        hashmap = collections.defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(word)):\n",
    "                hashmap[word[:i] + '*' + word[i + 1:]].append(word)\n",
    "        stack = [beginWord]\n",
    "        w_dict = {beginWord: [beginWord]}\n",
    "        while stack:\n",
    "            word = stack.pop()\n",
    "            if word == endWord:\n",
    "                return w_dict[word]\n",
    "            for i in range(len(word)):\n",
    "                if word[:i] + '*' + word[i + 1:] in hashmap:\n",
    "                    for tmp in hashmap[word[:i] + '*' + word[i + 1:]]:\n",
    "                        if tmp not in w_dict:\n",
    "                            w_dict[tmp] = w_dict[word] + [tmp]\n",
    "                            stack.append(tmp)\n",
    "        return []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        wordDict = dict.fromkeys(wordList)\n",
    "\n",
    "        def dfs(path, res, visited) -> bool:\n",
    "            if path[-1] == endWord:\n",
    "                res.append(list(path))\n",
    "                return True\n",
    "            \n",
    "            if path[-1] in visited:\n",
    "                return False \n",
    "            else:\n",
    "                visited.add(path[-1])\n",
    "\n",
    "            for i in range(len(path[-1])):\n",
    "                for alpha in 'qwertyuiopasdfghjklzxcvbnm':\n",
    "                    new = path[-1][0: i] + alpha + path[-1][i+1: ]\n",
    "                    #if new in path:\n",
    "                    #    continue \n",
    "                        \n",
    "                    if new in wordDict:\n",
    "                        if dfs(path+[new], res, visited) == True:\n",
    "                            return True \n",
    "            \n",
    "            return False \n",
    "        \n",
    "        res = []\n",
    "        visited = set()\n",
    "        dfs([beginWord, ], res, visited)\n",
    "        # print(res)\n",
    "        return res[0] if res else []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        # DFS\n",
    "        hashmap = collections.defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(word)):\n",
    "                hashmap[word[:i] + '*' + word[i + 1:]].append(word)\n",
    "        stack = [beginWord]\n",
    "        w_dict = {beginWord: [beginWord]}\n",
    "        while stack:\n",
    "            word = stack.pop()\n",
    "            if word == endWord:\n",
    "                return w_dict[word]\n",
    "            for i in range(len(word)):\n",
    "                if word[:i] + '*' + word[i + 1:] in hashmap:\n",
    "                    for tmp in hashmap[word[:i] + '*' + word[i + 1:]]:\n",
    "                        if tmp not in w_dict:\n",
    "                            w_dict[tmp] = w_dict[word] + [tmp]\n",
    "                            stack.append(tmp)\n",
    "        return []\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        # DFS\n",
    "        hashmap = collections.defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(word)):\n",
    "                hashmap[word[:i] + '*' + word[i + 1:]].append(word)\n",
    "        stack = [beginWord]\n",
    "        w_dict = {beginWord: [beginWord]}\n",
    "        while stack:\n",
    "            word = stack.pop()\n",
    "            if word == endWord:\n",
    "                return w_dict[word]\n",
    "            for i in range(len(word)):\n",
    "                if word[:i] + '*' + word[i + 1:] in hashmap:\n",
    "                    for tmp in hashmap[word[:i] + '*' + word[i + 1:]]:\n",
    "                        if tmp not in w_dict:\n",
    "                            w_dict[tmp] = w_dict[word] + [tmp]\n",
    "                            stack.append(tmp)\n",
    "        return []\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "\n",
    "        def can_transform(word_a, word_b):\n",
    "            if len(word_a) != len(word_b) or word_a == word_b:\n",
    "                return False\n",
    "            is_diff_once = False\n",
    "            for char_a, char_b in zip(word_a, word_b):\n",
    "                if char_a != char_b:\n",
    "                    if is_diff_once:\n",
    "                        return False\n",
    "                    is_diff_once = True\n",
    "            return True\n",
    "\n",
    "        seen = set()\n",
    "        def dfs(cur_word, words_path):\n",
    "            if cur_word == endWord:\n",
    "                return words_path\n",
    "            for nex_word in wordList:\n",
    "                if nex_word in seen:\n",
    "                    continue\n",
    "                if can_transform(cur_word, nex_word):\n",
    "                    seen.add(nex_word)\n",
    "                    res_path = dfs(nex_word, words_path + [nex_word])\n",
    "                    if res_path:\n",
    "                        return res_path\n",
    "            return []\n",
    "        \n",
    "        return dfs(beginWord, [beginWord])\n",
    "\n",
    "        # seen = set()\n",
    "        # seen.add(beginWord)\n",
    "        # def bfs():\n",
    "        #     queue = [(beginWord, [beginWord])]\n",
    "        #     while queue:\n",
    "        #         cur_word, cur_path = queue.pop(0)\n",
    "        #         for nex_word in wordList:\n",
    "        #             if nex_word not in seen:\n",
    "        #                 nex_word\n",
    "                \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import *\n",
    "from heapq import *\n",
    "from sys import *\n",
    "from math import *\n",
    "from itertools import *\n",
    "from functools import *\n",
    "from string import *\n",
    "from bisect import *\n",
    "from graphlib import *\n",
    "from sortedcontainers import *\n",
    "from copy import *\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        # DFS\n",
    "        hashmap = defaultdict(list)\n",
    "        for word in wordList:\n",
    "            for i in range(len(word)):\n",
    "                hashmap[word[:i] + '*' + word[i + 1:]].append(word)\n",
    "        stack = [beginWord]\n",
    "        w_dict = {beginWord: [beginWord]}\n",
    "        while stack:\n",
    "            word = stack.pop()\n",
    "            if word == endWord:\n",
    "                return w_dict[word]\n",
    "            for i in range(len(word)):\n",
    "                if word[:i] + '*' + word[i + 1:] in hashmap:\n",
    "                    for tmp in hashmap[word[:i] + '*' + word[i + 1:]]:\n",
    "                        if tmp not in w_dict:\n",
    "                            w_dict[tmp] = w_dict[word] + [tmp]\n",
    "                            stack.append(tmp)\n",
    "        return []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        if endWord not in set(wordList):return []\n",
    "        def check(num1,num2):\n",
    "            if num1==num2:return False\n",
    "            for i in range(len(num1)):\n",
    "                if num1[:i]==num2[:i] and num1[i+1:]==num2[i+1:]:\n",
    "                    return True\n",
    "            return False\n",
    "        visited = {c:False for c in wordList}\n",
    "        def dfs(acc,path):\n",
    "            if acc==endWord:\n",
    "                path.append(acc)\n",
    "                res.append(path)\n",
    "                # print('****',res)\n",
    "                return True\n",
    "            for c in wordList:\n",
    "                if visited[c]:continue\n",
    "                if check(acc,c):\n",
    "                    visited[c] = True\n",
    "                    if dfs(c,path+[acc]):\n",
    "                        return True\n",
    "                    # visited[c] = False\n",
    "            return False\n",
    "        res = [[]]\n",
    "        dfs(beginWord,[])\n",
    "        return res[-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "\n",
    "        def can_transform(word_a, word_b):\n",
    "            if len(word_a) != len(word_b) or word_a == word_b:\n",
    "                return False\n",
    "            is_diff_once = False\n",
    "            for char_a, char_b in zip(word_a, word_b):\n",
    "                if char_a != char_b:\n",
    "                    if is_diff_once:\n",
    "                        return False\n",
    "                    is_diff_once = True\n",
    "            return True\n",
    "\n",
    "        seen = set()\n",
    "        def dfs(cur_word, words_path):\n",
    "            if cur_word == endWord:\n",
    "                return words_path\n",
    "            for nex_word in wordList:\n",
    "                if nex_word in seen:\n",
    "                    continue\n",
    "                if can_transform(cur_word, nex_word):\n",
    "                    seen.add(nex_word)\n",
    "                    res_path = dfs(nex_word, words_path + [nex_word])\n",
    "                    if res_path:\n",
    "                        return res_path\n",
    "            return []\n",
    "        \n",
    "        return dfs(beginWord, [beginWord])\n",
    "\n",
    "        # seen = set()\n",
    "        # seen.add(beginWord)\n",
    "        # def bfs():\n",
    "        #     queue = [(beginWord, [beginWord])]\n",
    "        #     while queue:\n",
    "        #         cur_word, cur_path = queue.pop(0)\n",
    "        #         for nex_word in wordList:\n",
    "        #             if nex_word not in seen:\n",
    "        #                 nex_word\n",
    "                \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "\n",
    "        def can_transform(word_a, word_b):\n",
    "            if len(word_a) != len(word_b) or word_a == word_b:\n",
    "                return False\n",
    "            is_diff_once = False\n",
    "            for char_a, char_b in zip(word_a, word_b):\n",
    "                if char_a != char_b:\n",
    "                    if is_diff_once:\n",
    "                        return False\n",
    "                    is_diff_once = True\n",
    "            return True\n",
    "\n",
    "        seen = set()\n",
    "        def dfs(cur_word, words_path):\n",
    "            if cur_word == endWord:\n",
    "                return words_path\n",
    "            for nex_word in wordList:\n",
    "                if nex_word in seen:\n",
    "                    continue\n",
    "                if can_transform(cur_word, nex_word):\n",
    "                    seen.add(nex_word)\n",
    "                    res_path = dfs(nex_word, words_path + [nex_word])\n",
    "                    if res_path:\n",
    "                        return res_path\n",
    "            return []\n",
    "        \n",
    "        return dfs(beginWord, [beginWord])\n",
    "\n",
    "        # seen = set()\n",
    "        # seen.add(beginWord)\n",
    "        # def bfs():\n",
    "        #     queue = [(beginWord, [beginWord])]\n",
    "        #     while queue:\n",
    "        #         cur_word, cur_path = queue.pop(0)\n",
    "        #         for nex_word in wordList:\n",
    "        #             if nex_word not in seen:\n",
    "        #                 nex_word\n",
    "                \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        if endWord not in set(wordList):return []\n",
    "        def check(num1,num2):\n",
    "            if num1==num2:return False\n",
    "            for i in range(len(num1)):\n",
    "                if num1[:i]==num2[:i] and num1[i+1:]==num2[i+1:]:\n",
    "                    return True\n",
    "            return False\n",
    "        visited = {c:False for c in wordList}\n",
    "        def dfs(acc,path):\n",
    "            if acc==endWord:\n",
    "                path.append(acc)\n",
    "                res.append(path)\n",
    "                # print('****',res)\n",
    "                return True\n",
    "            for c in wordList:\n",
    "                if visited[c]:continue\n",
    "                if check(acc,c):\n",
    "                    visited[c] = True\n",
    "                    if dfs(c,path+[acc]):\n",
    "                        return True\n",
    "                    # visited[c] = False\n",
    "            return False\n",
    "        res = [[]]\n",
    "        dfs(beginWord,[])\n",
    "        return res[-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "        \n",
    "        wordDict = dict.fromkeys(wordList)\n",
    "\n",
    "        def backtracing(path: List, res: List, used: int) -> bool: \n",
    "            # print(path)\n",
    "            if path[-1] == endWord:\n",
    "                res.append(list(path))\n",
    "                return True\n",
    "\n",
    "            if path[-1] in visited:\n",
    "                return False \n",
    "            visited.add(path[-1])\n",
    "\n",
    "            for ri in range(len(path[-1])):\n",
    "                for c in 'abcdefghijklmnopqrstuvwxyz': \n",
    "                    w = path[-1][0:ri] + c + path[-1][ri+1: ]\n",
    "                    if w not in wordDict:\n",
    "                        continue \n",
    "\n",
    "                    if backtracing(path + [w], res, used) == True:\n",
    "                        return True \n",
    "\n",
    "            return False \n",
    "           \n",
    "        res = []\n",
    "        used = 0\n",
    "        visited = set()\n",
    "        flag = backtracing([beginWord], res, used)\n",
    "        # print(res)\n",
    "        return res[0] if res else []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "        \n",
    "        wordDict = dict.fromkeys(wordList)\n",
    "\n",
    "        def backtracing(path: List, res: List) -> bool: \n",
    "            # print(path)\n",
    "            if path[-1] == endWord:\n",
    "                res.append(list(path))\n",
    "                return True\n",
    "\n",
    "            if path[-1] in visited:\n",
    "                return False \n",
    "            visited.add(path[-1])\n",
    "\n",
    "            for ri in range(len(path[-1])):\n",
    "                for c in 'abcdefghijklmnopqrstuvwxyz': \n",
    "                    w = path[-1][0:ri] + c + path[-1][ri+1: ]\n",
    "                    if w not in wordDict:\n",
    "                        continue \n",
    "\n",
    "                    if backtracing(path + [w], res) == True:\n",
    "                        return True \n",
    "\n",
    "            return False \n",
    "           \n",
    "        res = []\n",
    "        visited = set()\n",
    "        flag = backtracing([beginWord], res)\n",
    "        # print(res)\n",
    "        return res[0] if res else []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        if endWord not in wordList:\n",
    "            return []\n",
    "        \n",
    "        wordDict = dict.fromkeys(wordList)\n",
    "\n",
    "        def backtracing(path: List, res: List, used: int) -> bool: \n",
    "            if path[-1] == endWord:\n",
    "                res.append(list(path))\n",
    "                return True\n",
    "\n",
    "            if path[-1] in visited:\n",
    "                return \n",
    "            \n",
    "            visited.add(path[-1])\n",
    "            # print(path)\n",
    "            for ri in range(len(path[-1])):\n",
    "                for c in 'abcdefghijklmnopqrstuvwxyz': \n",
    "                    w = path[-1][0:ri] + c + path[-1][ri+1: ]\n",
    "                    if w not in wordDict:\n",
    "                        continue \n",
    "\n",
    "                    if backtracing(path + [w], res, used) == True :\n",
    "                        return True \n",
    "\n",
    "            return False \n",
    "           \n",
    "        res = []\n",
    "        used = 0\n",
    "        visited = set()\n",
    "        flag = backtracing([beginWord], res, used)\n",
    "        # print(res)\n",
    "        return res[0] if res else []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[str]:\n",
    "        word_dic = defaultdict(set)\n",
    "        for word in wordList:\n",
    "            for i in range(len(word)):\n",
    "                word_dic[word[:i] + '*' + word[i+1:]].add(word)\n",
    "        res = []\n",
    "        path = [beginWord]\n",
    "        visited = set()\n",
    "        visited.add(beginWord)\n",
    "        def dfs(cur: str):\n",
    "            nonlocal res\n",
    "            if cur == endWord:\n",
    "                res = path\n",
    "                return\n",
    "            for i in range(len(cur)):\n",
    "                for word in word_dic[cur[:i] + '*' + cur[i+1:]]:\n",
    "                    if word not in visited:\n",
    "                        visited.add(word)\n",
    "                        path.append(word)\n",
    "                        dfs(word)\n",
    "                        if res:\n",
    "                            return\n",
    "                        path.pop()\n",
    "        dfs(beginWord)\n",
    "        return res"
   ]
  }
 ],
 "metadata": {},
 "nbformat": 4,
 "nbformat_minor": 2
}
